diff --git a/lib/gitlab/ci/config/node/configurable.rb b/lib/gitlab/ci/config/node/configurable.rb
index f26924fab26f6d300d46179d18fcd4613031496a..25b5c2c9e21fbdadfa953e3d5176910ac0e65a4a 100644
--- a/lib/gitlab/ci/config/node/configurable.rb
+++ b/lib/gitlab/ci/config/node/configurable.rb
@@ -33,12 +33,12 @@ module Gitlab
 
           class_methods do
             def nodes
-              Hash[@allowed_nodes.map { |key, factory| [key, factory.dup] }]
+              Hash[@nodes.map { |key, factory| [key, factory.dup] }]
             end
 
             private
 
-            def allow_node(symbol, entry_class, metadata)
+            def node(symbol, entry_class, metadata)
               factory = Node::Factory.new(entry_class)
                 .with(description: metadata[:description])
 
@@ -47,7 +47,7 @@ module Gitlab
                 @nodes[symbol].try(:value)
               end
 
-              (@allowed_nodes ||= {}).merge!(symbol => factory)
+              (@nodes ||= {}).merge!(symbol => factory)
             end
           end
         end
diff --git a/lib/gitlab/ci/config/node/entry.rb b/lib/gitlab/ci/config/node/entry.rb
index 91f3fd0e236eb22d75fd9da28070918585fa760f..444a276d5c9c834b940d2013c18ca05e15bd3f49 100644
--- a/lib/gitlab/ci/config/node/entry.rb
+++ b/lib/gitlab/ci/config/node/entry.rb
@@ -52,6 +52,9 @@ module Gitlab
             @config
           end
 
+          def self.default
+          end
+
           def self.nodes
             {}
           end
diff --git a/lib/gitlab/ci/config/node/factory.rb b/lib/gitlab/ci/config/node/factory.rb
index dbf027b6d8e5528cb830dd8ba73d4e22e0da549a..2271c386df6f4879f234288c9f5f7ed22021e43c 100644
--- a/lib/gitlab/ci/config/node/factory.rb
+++ b/lib/gitlab/ci/config/node/factory.rb
@@ -8,8 +8,8 @@ module Gitlab
         class Factory
           class InvalidFactory < StandardError; end
 
-          def initialize(entry_class)
-            @entry_class = entry_class
+          def initialize(node)
+            @node = node
             @attributes = {}
           end
 
@@ -19,14 +19,15 @@ module Gitlab
           end
 
           def undefine!
-            @entry_class = Node::Undefined
+            @attributes[:value] = @node.dup
+            @node = Node::Undefined
             self
           end
 
           def create!
             raise InvalidFactory unless @attributes.has_key?(:value)
 
-            @entry_class.new(@attributes[:value]).tap do |entry|
+            @node.new(@attributes[:value]).tap do |entry|
               entry.description = @attributes[:description]
               entry.key = @attributes[:key]
             end
diff --git a/lib/gitlab/ci/config/node/global.rb b/lib/gitlab/ci/config/node/global.rb
index 3bb6f98ed0f852cb843d01f3ecc25f33f4ee1fa0..b5d177c52852525566a19824897dbb4ba86470b3 100644
--- a/lib/gitlab/ci/config/node/global.rb
+++ b/lib/gitlab/ci/config/node/global.rb
@@ -9,19 +9,19 @@ module Gitlab
         class Global < Entry
           include Configurable
 
-          allow_node :before_script, Script,
+          node :before_script, Script,
             description: 'Script that will be executed before each job.'
 
-          allow_node :image, Image,
+          node :image, Image,
             description: 'Docker image that will be used to execute jobs.'
 
-          allow_node :services, Services,
+          node :services, Services,
             description: 'Docker images that will be linked to the container.'
 
-          allow_node :after_script, Script,
+          node :after_script, Script,
             description: 'Script that will be executed after each job.'
 
-          allow_node :variables, Variables,
+          node :variables, Variables,
             description: 'Environment variables that will be used.'
         end
       end
diff --git a/lib/gitlab/ci/config/node/undefined.rb b/lib/gitlab/ci/config/node/undefined.rb
index a812d803f3ea031d930b86a71a0c828165073967..e8a69b810e0b4ccb5a477494b7b308c2494291da 100644
--- a/lib/gitlab/ci/config/node/undefined.rb
+++ b/lib/gitlab/ci/config/node/undefined.rb
@@ -3,17 +3,21 @@ module Gitlab
     class Config
       module Node
         ##
-        # This class represents a configuration entry that is not defined
-        # in configuration file.
+        # This class represents an undefined entry node.
         #
-        # This implements a Null Object pattern.
+        # It takes original entry class as configuration and returns default
+        # value of original entry as self value.
         #
-        # It can be initialized using a default value of entry that is not
-        # present in configuration.
         #
         class Undefined < Entry
-          def method_missing(*)
-            nil
+          include Validatable
+
+          validations do
+            validates :config, type: Class
+          end
+
+          def value
+            @config.default
           end
         end
       end
diff --git a/lib/gitlab/ci/config/node/variables.rb b/lib/gitlab/ci/config/node/variables.rb
index 5decd777bdba596a10f761935f2c5ae96dc39332..fd3ce8715a936419d72ce0081531b10c3e7b3fd6 100644
--- a/lib/gitlab/ci/config/node/variables.rb
+++ b/lib/gitlab/ci/config/node/variables.rb
@@ -13,7 +13,11 @@ module Gitlab
           end
 
           def value
-            @config || {}
+            @config || self.class.default
+          end
+
+          def self.default
+            {}
           end
         end
       end
diff --git a/spec/lib/gitlab/ci/config/node/configurable_spec.rb b/spec/lib/gitlab/ci/config/node/configurable_spec.rb
index 9bbda6e73967ba358f44808a5cf1bca7784210f5..2ac436cb4b21230d1b553e201f211e2a35cd29e0 100644
--- a/spec/lib/gitlab/ci/config/node/configurable_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/configurable_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::Ci::Config::Node::Configurable do
   describe 'configured nodes' do
     before do
       node.class_eval do
-        allow_node :object, Object, description: 'test object'
+        node :object, Object, description: 'test object'
       end
     end
 
diff --git a/spec/lib/gitlab/ci/config/node/undefined_spec.rb b/spec/lib/gitlab/ci/config/node/undefined_spec.rb
index 2d01a8a6ec82895475d57a4c7e622c2ecae27051..5ded0504a3fbebd6b15f17d47c7002fd03b52025 100644
--- a/spec/lib/gitlab/ci/config/node/undefined_spec.rb
+++ b/spec/lib/gitlab/ci/config/node/undefined_spec.rb
@@ -1,23 +1,34 @@
 require 'spec_helper'
 
 describe Gitlab::Ci::Config::Node::Undefined do
-  let(:entry) { described_class.new('some value') }
+  let(:undefined) { described_class.new(entry) }
+  let(:entry) { Class.new }
 
   describe '#leaf?' do
     it 'is leaf node' do
-      expect(entry).to be_leaf
+      expect(undefined).to be_leaf
     end
   end
 
-  describe '#any_method' do
-    it 'responds with nil' do
-      expect(entry.any_method).to be nil
+  describe '#valid?' do
+    it 'is always valid' do
+      expect(undefined).to be_valid
+    end
+  end
+
+  describe '#errors' do
+    it 'is does not contain errors' do
+      expect(undefined.errors).to be_empty
     end
   end
 
   describe '#value' do
-    it 'returns configured value' do
-      expect(entry.value).to eq 'some value'
+    before do
+      allow(entry).to receive(:default).and_return('some value')
+    end
+
+    it 'returns default value for entry that is undefined' do
+      expect(undefined.value).to eq 'some value'
     end
   end
 end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 2a5d132db7bb6f218df734d21f3227e1d7e84afd..bc5a5e431033a5c373866bf537aa078df308ac74 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -40,38 +40,38 @@ describe Gitlab::Ci::Config do
         end
       end
     end
+  end
 
-    context 'when config is invalid' do
-      context 'when yml is incorrect' do
-        let(:yml) { '// invalid' }
+  context 'when config is invalid' do
+    context 'when yml is incorrect' do
+      let(:yml) { '// invalid' }
 
-        describe '.new' do
-          it 'raises error' do
-            expect { config }.to raise_error(
-              Gitlab::Ci::Config::Loader::FormatError,
-              /Invalid configuration format/
-            )
-          end
+      describe '.new' do
+        it 'raises error' do
+          expect { config }.to raise_error(
+            Gitlab::Ci::Config::Loader::FormatError,
+            /Invalid configuration format/
+          )
         end
       end
+    end
 
-      context 'when config logic is incorrect' do
-        let(:yml) { 'before_script: "ls"' }
+    context 'when config logic is incorrect' do
+      let(:yml) { 'before_script: "ls"' }
 
-        describe '#valid?' do
-          it 'is not valid' do
-            expect(config).not_to be_valid
-          end
+      describe '#valid?' do
+        it 'is not valid' do
+          expect(config).not_to be_valid
+        end
 
-          it 'has errors' do
-            expect(config.errors).not_to be_empty
-          end
+        it 'has errors' do
+          expect(config.errors).not_to be_empty
         end
+      end
 
-        describe '#errors' do
-          it 'returns an array of strings' do
-            expect(config.errors).to all(be_an_instance_of(String))
-          end
+      describe '#errors' do
+        it 'returns an array of strings' do
+          expect(config.errors).to all(be_an_instance_of(String))
         end
       end
     end