diff --git a/pkg/document/selectors.go b/pkg/document/selectors.go
index 71c4ea82d..2d3384382 100644
--- a/pkg/document/selectors.go
+++ b/pkg/document/selectors.go
@@ -18,9 +18,9 @@ import (
 	"fmt"
 	"strings"
 
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/meta"
 	"k8s.io/apimachinery/pkg/runtime"
-
 	"sigs.k8s.io/kustomize/api/types"
 	"sigs.k8s.io/kustomize/kyaml/resid"
 )
@@ -104,6 +104,15 @@ func (s Selector) ByObject(obj runtime.Object, scheme *runtime.Scheme) (Selector
 	return result, nil
 }
 
+// ByObjectReference select by ObjectReference
+func (s Selector) ByObjectReference(objRef *corev1.ObjectReference) Selector {
+	refGVK := objRef.GroupVersionKind()
+	return NewSelector().
+		ByGvk(refGVK.Group, refGVK.Version, refGVK.Kind).
+		ByName(objRef.Name).
+		ByNamespace(objRef.Namespace)
+}
+
 // String is a convenience function which dumps all relevant information about a Selector in the following format:
 // [Key1=Value1, Key2=Value2, ...]
 func (s Selector) String() string {
diff --git a/pkg/document/selectors_test.go b/pkg/document/selectors_test.go
index 39583c9e0..5b14d4f0f 100644
--- a/pkg/document/selectors_test.go
+++ b/pkg/document/selectors_test.go
@@ -208,3 +208,41 @@ func TestSelectorToObject(t *testing.T) {
 		})
 	}
 }
+
+func TestSelectorByObjRef(t *testing.T) {
+	tests := []struct {
+		name        string
+		objRef      *k8sv1.ObjectReference
+		expectedSel document.Selector
+	}{
+		{
+			name: "Selector with GVK, name and namespace",
+			objRef: &k8sv1.ObjectReference{
+				Kind:       "TestKind",
+				Name:       "TestName",
+				APIVersion: "api.version/v1",
+				Namespace:  "TestNamespace",
+			},
+			expectedSel: document.Selector{
+				Selector: types.Selector{
+					ResId: resid.ResId{
+						Gvk: resid.Gvk{
+							Group:   "api.version",
+							Version: "v1",
+							Kind:    "TestKind",
+						},
+						Name:      "TestName",
+						Namespace: "TestNamespace",
+					},
+				},
+			},
+		},
+	}
+	for _, test := range tests {
+		tt := test
+		t.Run(tt.name, func(t *testing.T) {
+			actualSel := document.NewSelector().ByObjectReference(tt.objRef)
+			assert.Equal(t, tt.expectedSel, actualSel)
+		})
+	}
+}
diff --git a/pkg/phase/client.go b/pkg/phase/client.go
index 579670077..f8c2decf2 100644
--- a/pkg/phase/client.go
+++ b/pkg/phase/client.go
@@ -63,24 +63,10 @@ type phase struct {
 	processor events.EventProcessor
 }
 
-func (p *phase) defaultBundleFactory() document.BundleFactoryFunc {
-	return document.BundleFactoryFromDocRoot(p.DocumentRoot)
-}
-
-func (p *phase) defaultDocFactory() document.DocFactoryFunc {
-	return func() (document.Document, error) {
-		return p.helper.ExecutorDoc(ifc.ID{Name: p.apiObj.Name, Namespace: p.apiObj.Namespace})
-	}
-}
-
 // Executor returns executor interface associated with the phase
 func (p *phase) Executor() (ifc.Executor, error) {
-	return p.executor(p.defaultDocFactory(), p.defaultBundleFactory())
-}
-
-func (p *phase) executor(docFactory document.DocFactoryFunc,
-	bundleFactory document.BundleFactoryFunc) (ifc.Executor, error) {
-	executorDoc, err := docFactory()
+	executorDoc, err := p.helper.PhaseConfigBundle().SelectOne(
+		document.NewSelector().ByObjectReference(p.apiObj.Config.ExecutorRef))
 	if err != nil {
 		return nil, err
 	}
@@ -112,7 +98,7 @@ func (p *phase) executor(docFactory document.DocFactoryFunc,
 	return executorFactory(
 		ifc.ExecutorConfig{
 			ClusterMap:        cMap,
-			BundleFactory:     bundleFactory,
+			BundleFactory:     document.BundleFactoryFromDocRoot(p.DocumentRoot),
 			PhaseName:         p.apiObj.Name,
 			KubeConfig:        kubeconf,
 			ExecutorDocument:  executorDoc,
diff --git a/pkg/phase/client_test.go b/pkg/phase/client_test.go
index 8c9576cb5..bc953f6aa 100644
--- a/pkg/phase/client_test.go
+++ b/pkg/phase/client_test.go
@@ -233,13 +233,6 @@ func TestPhaseValidate(t *testing.T) {
 			registryFunc: fakeRegistry,
 			errContains:  "executor identified by 'airshipit.org/v1alpha1, Kind=SomeExecutor' is not found",
 		},
-		{
-			name:         "Error no executor",
-			configFunc:   testConfig,
-			phaseID:      ifc.ID{Name: "no_executor_phase"},
-			registryFunc: fakeRegistry,
-			errContains:  "Phase name 'no_executor_phase', namespace '' must have executorRef field defined in config",
-		},
 		{
 			name:       "Error executor validate",
 			configFunc: testConfig,
diff --git a/pkg/phase/executors/container.go b/pkg/phase/executors/container.go
index b47e9abed..a3489d401 100644
--- a/pkg/phase/executors/container.go
+++ b/pkg/phase/executors/container.go
@@ -182,12 +182,7 @@ func (c *ContainerExecutor) Render(w io.Writer, o ifc.RenderOptions) error {
 func (c *ContainerExecutor) setConfig() error {
 	if c.Container.ConfigRef != nil {
 		log.Debugf("Config reference is specified, looking for the object in config ref: '%v'", c.Container.ConfigRef)
-		gvk := c.Container.ConfigRef.GroupVersionKind()
-		selector := document.NewSelector().
-			ByName(c.Container.ConfigRef.Name).
-			ByNamespace(c.Container.ConfigRef.Namespace).
-			ByGvk(gvk.Group, gvk.Version, gvk.Kind)
-		doc, err := c.Options.PhaseConfigBundle.SelectOne(selector)
+		doc, err := c.Options.PhaseConfigBundle.SelectOne(document.NewSelector().ByObjectReference(c.Container.ConfigRef))
 		if err != nil {
 			return err
 		}
diff --git a/pkg/phase/helper.go b/pkg/phase/helper.go
index 03751d57b..b93c5989f 100644
--- a/pkg/phase/helper.go
+++ b/pkg/phase/helper.go
@@ -110,6 +110,13 @@ func (helper *Helper) Phase(phaseID ifc.ID) (*v1alpha1.Phase, error) {
 	if err = doc.ToAPIObject(phase, v1alpha1.Scheme); err != nil {
 		return nil, err
 	}
+	// Phase must contain an executor
+	if phase.Config.ExecutorRef == nil {
+		return nil, errors.ErrExecutorRefNotDefined{
+			PhaseName:      phase.Name,
+			PhaseNamespace: phase.Namespace,
+		}
+	}
 	return phase, nil
 }
 
@@ -271,19 +278,9 @@ func (helper *Helper) ExecutorDoc(phaseID ifc.ID) (document.Document, error) {
 		return nil, err
 	}
 
-	phaseConfig := phaseObj.Config
-	if phaseConfig.ExecutorRef == nil {
-		return nil, errors.ErrExecutorRefNotDefined{PhaseName: phaseID.Name, PhaseNamespace: phaseID.Namespace}
-	}
-
 	// Searching executor configuration document referenced in
 	// phase configuration
-	refGVK := phaseConfig.ExecutorRef.GroupVersionKind()
-	selector := document.NewSelector().
-		ByGvk(refGVK.Group, refGVK.Version, refGVK.Kind).
-		ByName(phaseConfig.ExecutorRef.Name).
-		ByNamespace(phaseConfig.ExecutorRef.Namespace)
-	return helper.phaseConfigBundle.SelectOne(selector)
+	return helper.phaseConfigBundle.SelectOne(document.NewSelector().ByObjectReference(phaseObj.Config.ExecutorRef))
 }
 
 // TargetPath returns manifest root
diff --git a/pkg/phase/helper_test.go b/pkg/phase/helper_test.go
index 3088b05ac..493a4f3d2 100644
--- a/pkg/phase/helper_test.go
+++ b/pkg/phase/helper_test.go
@@ -75,6 +75,12 @@ func TestHelperPhase(t *testing.T) {
 			phaseID:     ifc.ID{Name: "some_name"},
 			errContains: "found no documents",
 		},
+		{
+			name:        "Error no executor",
+			config:      testConfig,
+			phaseID:     ifc.ID{Name: "no_executor_phase"},
+			errContains: "Phase name 'no_executor_phase', namespace '' must have executorRef field defined in config",
+		},
 		{
 			name: "Error bundle path doesn't exist",
 			config: func(t *testing.T) *config.Config {
@@ -95,6 +101,7 @@ func TestHelperPhase(t *testing.T) {
 				require.Error(t, err)
 				return
 			}
+			require.NoError(t, err)
 			require.NotNil(t, helper)
 			actualPhase, actualErr := helper.Phase(tt.phaseID)
 			if tt.errContains != "" {
diff --git a/pkg/phase/testdata/valid_site_with_doc_prefix/phases/sample.yaml b/pkg/phase/testdata/valid_site_with_doc_prefix/phases/sample.yaml
index abe9b0007..949a6c59b 100644
--- a/pkg/phase/testdata/valid_site_with_doc_prefix/phases/sample.yaml
+++ b/pkg/phase/testdata/valid_site_with_doc_prefix/phases/sample.yaml
@@ -3,4 +3,8 @@ kind: Phase
 metadata:
   name: sample
 config:
+  executorRef:
+    apiVersion: airshipit.org/v1alpha1
+    kind: SomeExecutor
+    name: executor-name
   documentEntryPoint: entrypoint
\ No newline at end of file