You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ib...@apache.org on 2021/03/01 10:37:39 UTC

[ignite-3] branch main updated: IGNITE-14230 Port DynamicConfiguration to new underlying configuration framework. (#56)

This is an automated email from the ASF dual-hosted git repository.

ibessonov pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 5f715c0  IGNITE-14230 Port DynamicConfiguration to new underlying configuration framework. (#56)
5f715c0 is described below

commit 5f715c0d299f97f53efe8344ad68c342a6a2e3eb
Author: ibessonov <be...@gmail.com>
AuthorDate: Mon Mar 1 13:37:31 2021 +0300

    IGNITE-14230 Port DynamicConfiguration to new underlying configuration framework. (#56)
---
 .../processor/internal/AbstractProcessorTest.java  |   6 +-
 .../processor/internal/ConfigSet.java              |  49 +-
 .../processor/internal/ITProcessorTest.java        |  62 +--
 .../processor/internal/ParsedClass.java            |  12 +
 .../configuration/processor/internal/Types.java    |  52 --
 .../processor/internal/ConfigurationNode.java      |  53 --
 .../processor/internal/Processor.java              | 591 +++------------------
 .../configuration/processor/internal/Utils.java    |  14 +-
 .../internal/pojo/ChangeClassGenerator.java        |  87 ---
 .../processor/internal/pojo/ClassGenerator.java    | 127 -----
 .../processor/internal/pojo/FieldMapping.java      |  52 --
 .../internal/pojo/InitClassGenerator.java          |  83 ---
 .../internal/pojo/ViewClassGenerator.java          |  79 ---
 .../sample/LocalConfigurationSchema.java           |   3 +-
 .../sample/NetworkConfigurationSchema.java         |   3 +-
 .../ignite/configuration/sample/UsageTest.java     | 119 +++--
 .../sample/storage/ConfigurationChangerTest.java   |  39 +-
 .../ignite/configuration/ConfigurationChanger.java |  92 ++--
 .../configuration/ConfigurationProperty.java       |   9 -
 .../configuration/ConfigurationRegistry.java       |  32 +-
 .../ignite/configuration/ConfigurationTree.java    |  10 +
 .../ignite/configuration/ConfigurationValue.java   |  12 +
 .../apache/ignite/configuration/Configurator.java  |  98 +---
 .../org/apache/ignite/configuration/RootKey.java   |   7 +-
 .../configuration/internal/ConfigurationNode.java  | 132 +++++
 .../internal/DynamicConfiguration.java             | 122 ++---
 .../configuration/internal/DynamicProperty.java    | 182 ++-----
 .../ignite/configuration/internal/Modifier.java    |  47 --
 .../internal/NamedListConfiguration.java           | 102 ++--
 .../configuration/{ => internal}/RootKeyImpl.java  |  28 +-
 .../internal/selector/BaseSelectors.java           | 157 ------
 .../configuration/internal/selector/Selector.java  |  39 --
 .../selector/SelectorNotFoundException.java        |  33 --
 .../internal/util/ConfigurationUtil.java           |  19 +
 .../configuration/tree/ConfigurationSource.java    |   4 +-
 .../configuration/tree/ConstructableTreeNode.java  |   2 +-
 .../ignite/configuration/tree/NamedListNode.java   |   2 +-
 .../ITScaleCubeNetworkClusterMessagingTest.java    |   6 +-
 .../java/org/apache/ignite/rest/RestModule.java    |  30 +-
 .../rest/presentation/json/JsonPresentation.java   |  21 +-
 .../ignite/configuration/ConfigurationModule.java  |  37 +-
 41 files changed, 655 insertions(+), 1999 deletions(-)

diff --git a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/AbstractProcessorTest.java b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/AbstractProcessorTest.java
index 0c316ed..9b7aa2f 100644
--- a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/AbstractProcessorTest.java
+++ b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/AbstractProcessorTest.java
@@ -63,16 +63,18 @@ public class AbstractProcessorTest {
      */
     protected static ConfigSet getConfigSet(ClassName clazz, final Map<ClassName, JavaFileObject> generatedClasses) {
         final ClassName configurationName = Utils.getConfigurationName(clazz);
+        final ClassName nodeName = Utils.getNodeName(clazz);
         final ClassName viewName = Utils.getViewName(clazz);
         final ClassName initName = Utils.getInitName(clazz);
         final ClassName changeName = Utils.getChangeName(clazz);
 
-        final JavaFileObject configurationFileObject = generatedClasses.get(configurationName);
+        final JavaFileObject configurationClass = generatedClasses.get(configurationName);
+        final JavaFileObject nodeClass = generatedClasses.get(nodeName);
         final JavaFileObject viewClass = generatedClasses.get(viewName);
         final JavaFileObject initClass = generatedClasses.get(initName);
         final JavaFileObject changeClass = generatedClasses.get(changeName);
 
-        return new ConfigSet(configurationFileObject, viewClass, initClass, changeClass);
+        return new ConfigSet(configurationClass, nodeClass, viewClass, initClass, changeClass);
     }
 
     /**
diff --git a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ConfigSet.java b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ConfigSet.java
index c5966ab..6b0ab23 100644
--- a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ConfigSet.java
+++ b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ConfigSet.java
@@ -29,6 +29,9 @@ public class ConfigSet {
     /** Configuration class. */
     private final JavaFileObject configurationClass;
 
+    /** Configuration node class. */
+    private final JavaFileObject nodeClass;
+
     /** VIEW class. */
     private final JavaFileObject viewClass;
 
@@ -41,41 +44,26 @@ public class ConfigSet {
     /** Parsed configuration class. */
     private final ParsedClass conf;
 
-    /** Parsed VIEW class. */
-    private final ParsedClass view;
-
-    /** Parsed INIT class. */
-    private final ParsedClass init;
-
-    /** Parsed CHANGE class. */
-    private final ParsedClass change;
+    /** Parsed node class. */
+    private final ParsedClass node;
 
     /** Constructor. */
-    public ConfigSet(JavaFileObject configurationClass, JavaFileObject viewClass, JavaFileObject initClass, JavaFileObject changeClass) {
+    public ConfigSet(JavaFileObject configurationClass, JavaFileObject nodeClass, JavaFileObject viewClass, JavaFileObject initClass, JavaFileObject changeClass) {
         this.configurationClass = configurationClass;
         this.viewClass = viewClass;
         this.initClass = initClass;
         this.changeClass = changeClass;
+        this.nodeClass = nodeClass;
 
         if (configurationClass != null)
             this.conf = parse(configurationClass);
         else
             this.conf = null;
 
-        if (viewClass != null)
-            this.view = parse(viewClass);
-        else
-            this.view = null;
-
-        if (initClass != null)
-            this.init = parse(initClass);
-        else
-            this.init = null;
-
-        if (changeClass != null)
-            this.change = parse(changeClass);
+        if (nodeClass != null)
+            this.node = parse(nodeClass);
         else
-            this.change = null;
+            this.node = null;
     }
 
     /**
@@ -98,7 +86,7 @@ public class ConfigSet {
      * @return {@code true} if all required classes were generated.
      */
     public boolean allGenerated() {
-        return configurationClass != null && viewClass != null && initClass != null && changeClass != null;
+        return configurationClass != null && nodeClass != null && viewClass != null && initClass != null && changeClass != null;
     }
 
     /** */
@@ -106,18 +94,7 @@ public class ConfigSet {
         return conf;
     }
 
-    /** */
-    public ParsedClass getViewClass() {
-        return view;
-    }
-
-    /** */
-    public ParsedClass getInitClass() {
-        return init;
-    }
-
-    /** */
-    public ParsedClass getChangeClass() {
-        return change;
+    public ParsedClass getNodeClass() {
+        return node;
     }
 }
diff --git a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ITProcessorTest.java b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ITProcessorTest.java
index dce8d54..84812ff 100644
--- a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ITProcessorTest.java
+++ b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ITProcessorTest.java
@@ -18,11 +18,11 @@ package org.apache.ignite.configuration.processor.internal;
 
 import com.google.testing.compile.Compilation;
 import com.squareup.javapoet.ClassName;
-import org.hamcrest.MatcherAssert;
 import org.junit.jupiter.api.Test;
 
 import static org.apache.ignite.configuration.processor.internal.HasFieldMatcher.hasFields;
 import static org.apache.ignite.configuration.processor.internal.HasMethodMatcher.hasMethods;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -46,56 +46,40 @@ public class ITProcessorTest extends AbstractProcessorTest {
 
         assertNotEquals(Compilation.Status.FAILURE, status.status());
 
-        assertEquals(11, batch.generated().size());
+        assertEquals(6, batch.generated().size());
 
         final ConfigSet classSet = batch.getBySchema(testConfigurationSchema);
 
         assertTrue(classSet.allGenerated());
 
-        MatcherAssert.assertThat(
-            classSet.getViewClass(),
+        assertThat(
+            classSet.getNodeClass(),
             hasFields(
-                "value1", Types.STRING,
-                "primitiveLong", Types.LONG,
-                "primitiveInt", Types.INT,
-                "stringArray", Types.STRING_ARRAY
+                "value1", String.class.getCanonicalName(),
+                "primitiveLong", Long.class.getCanonicalName(),
+                "primitiveInt", Integer.class.getCanonicalName(),
+                "stringArray", String[].class.getCanonicalName()
             )
         );
 
-        MatcherAssert.assertThat(
-            classSet.getViewClass(),
-            hasMethods(
-                "value1()", Types.STRING,
-                "primitiveLong()", Types.LONG,
-                "primitiveInt()", Types.INT,
-                "stringArray()", Types.STRING_ARRAY
-            )
-        );
+        String nodeClassName = classSet.getNodeClass().getClassName();
 
-        MatcherAssert.assertThat(
-            classSet.getInitClass(),
-            hasFields(
-                "value1", Types.STRING,
-                "primitiveLong", Types.LONG,
-                "primitiveInt", Types.INT,
-                "stringArray", Types.STRING_ARRAY
-            )
-        );
-
-        String initTypeName = Types.typeName(packageName, "InitTest");
-
-        MatcherAssert.assertThat(
-            classSet.getInitClass(),
+        assertThat(
+            classSet.getNodeClass(),
             hasMethods(
-                "value1()", Types.STRING,
-                "primitiveLong()", Types.LONG,
-                "primitiveInt()", Types.INT,
-                "withValue1(java.lang.String)", initTypeName,
-                "withPrimitiveLong(java.lang.Long)", initTypeName,
-                "withPrimitiveInt(java.lang.Integer)", initTypeName,
-                "withStringArray(java.lang.String[])", initTypeName
+                "value1()", String.class.getCanonicalName(),
+                "primitiveLong()", long.class.getCanonicalName(),
+                "primitiveInt()", int.class.getCanonicalName(),
+                "stringArray()", String[].class.getCanonicalName(),
+                "initValue1(java.lang.String)", nodeClassName,
+                "initPrimitiveLong(long)", nodeClassName,
+                "initPrimitiveInt(int)", nodeClassName,
+                "initStringArray(java.lang.String[])", nodeClassName,
+                "changeValue1(java.lang.String)", nodeClassName,
+                "changePrimitiveLong(long)", nodeClassName,
+                "changePrimitiveInt(int)", nodeClassName,
+                "changeStringArray(java.lang.String[])", nodeClassName
             )
         );
     }
-
 }
diff --git a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ParsedClass.java b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ParsedClass.java
index 15502b7..fb980bd 100644
--- a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ParsedClass.java
+++ b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/ParsedClass.java
@@ -46,6 +46,9 @@ public class ParsedClass {
     /** Class constructors by signature. */
     private final Map<String, CtConstructor<?>> constructors;
 
+    /** Class name. */
+    private final String qualifiedName;
+
     /**
      * Constructor.
      * @param cls Class info.
@@ -53,6 +56,8 @@ public class ParsedClass {
     public ParsedClass(CtClass<?> cls) {
         this.cls = cls;
 
+        this.qualifiedName = cls.getQualifiedName();
+
         this.fields = cls.getAllFields()
             .stream()
             .collect(Collectors.toMap(CtReference::getSimpleName, Functions.identity()));
@@ -67,6 +72,13 @@ public class ParsedClass {
     }
 
     /**
+     * @return Qualified class name.
+     */
+    public String getClassName() {
+        return qualifiedName;
+    }
+
+    /**
      * Get method name from method meta info.
      * @param method Method meta info.
      * @return Method name.
diff --git a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/Types.java b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/Types.java
deleted file mode 100644
index 108731e..0000000
--- a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/configuration/processor/internal/Types.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal;
-
-/**
- * Type names for testing.
- */
-public class Types {
-    /** Java lang package name. */
-    private static final String PKG_JAVA_LANG = "java.lang.";
-
-    /** Integer. */
-    public static final String INT = PKG_JAVA_LANG + "Integer";
-
-    /** Long. */
-    public static final String LONG = PKG_JAVA_LANG + "Long";
-
-    /** String. */
-    public static final String STRING = PKG_JAVA_LANG + "String";
-
-    /** String array. */
-    public static final String STRING_ARRAY = PKG_JAVA_LANG + "String[]";
-
-    /** Double. */
-    public static final String DOUBLE = PKG_JAVA_LANG + "Double";
-
-    /**
-     * Get type name by package name and class name.
-     * @param packageName Package name.
-     * @param className Class name.
-     * @return Type name.
-     */
-    public static String typeName(String packageName, String className) {
-        return String.format("%s.%s", packageName, className);
-    }
-
-}
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/ConfigurationNode.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/ConfigurationNode.java
deleted file mode 100644
index 2bbd637..0000000
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/ConfigurationNode.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal;
-
-import com.squareup.javapoet.TypeName;
-
-/**
- * Configuration element with a reference to its parent and with an original name.
- */
-public class ConfigurationNode extends ConfigurationElement {
-    /** Configuration parent. */
-    private final ConfigurationNode parent;
-
-    /** Original name of configuration element. */
-    private final String originalName;
-
-    /** Constructor. */
-    public ConfigurationNode(TypeName type, String name, String originalName, TypeName view, TypeName init, TypeName change, ConfigurationNode parent) {
-        super(type, name, view, init, change);
-        this.originalName = originalName;
-        this.parent = parent;
-    }
-
-    /**
-     * Get configuration parent.
-     */
-    public ConfigurationNode getParent() {
-        return parent;
-    }
-
-    /**
-     * Get original name of configuration element.
-     */
-    public String getOriginalName() {
-        return originalName;
-    }
-
-}
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
index 33a85d5..2ec61bf 100644
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
+++ b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
@@ -30,22 +30,15 @@ import com.squareup.javapoet.TypeSpec;
 import com.squareup.javapoet.TypeVariableName;
 import com.squareup.javapoet.WildcardTypeName;
 import java.io.IOException;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
 import java.util.ArrayList;
-import java.util.Comparator;
-import java.util.Deque;
+import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
-import java.util.stream.IntStream;
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.Filer;
 import javax.annotation.processing.ProcessingEnvironment;
@@ -60,10 +53,10 @@ import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.MirroredTypesException;
 import javax.lang.model.type.TypeMirror;
 import javax.lang.model.util.Elements;
+import org.apache.ignite.configuration.ConfigurationChanger;
 import org.apache.ignite.configuration.ConfigurationRegistry;
 import org.apache.ignite.configuration.ConfigurationTree;
 import org.apache.ignite.configuration.ConfigurationValue;
-import org.apache.ignite.configuration.Configurator;
 import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.annotation.Config;
 import org.apache.ignite.configuration.annotation.ConfigValue;
@@ -73,12 +66,6 @@ import org.apache.ignite.configuration.annotation.Value;
 import org.apache.ignite.configuration.internal.DynamicConfiguration;
 import org.apache.ignite.configuration.internal.DynamicProperty;
 import org.apache.ignite.configuration.internal.NamedListConfiguration;
-import org.apache.ignite.configuration.internal.selector.BaseSelectors;
-import org.apache.ignite.configuration.internal.selector.Selector;
-import org.apache.ignite.configuration.internal.validation.MemberKey;
-import org.apache.ignite.configuration.processor.internal.pojo.ChangeClassGenerator;
-import org.apache.ignite.configuration.processor.internal.pojo.InitClassGenerator;
-import org.apache.ignite.configuration.processor.internal.pojo.ViewClassGenerator;
 import org.apache.ignite.configuration.processor.internal.validation.ValidationGenerator;
 import org.apache.ignite.configuration.tree.ConfigurationSource;
 import org.apache.ignite.configuration.tree.ConfigurationVisitor;
@@ -104,23 +91,6 @@ public class Processor extends AbstractProcessor {
     /** Wildcard (?) TypeName. */
     private static final TypeName WILDCARD = WildcardTypeName.subtypeOf(Object.class);
 
-    /** Type of Configurator (every DynamicConfiguration has a Configurator field). */
-    private static final ParameterizedTypeName CONFIGURATOR_TYPE = ParameterizedTypeName.get(
-        ClassName.get(Configurator.class),
-        WildcardTypeName.subtypeOf(
-            ParameterizedTypeName.get(ClassName.get(DynamicConfiguration.class), WILDCARD, WILDCARD, WILDCARD)
-        )
-    );
-
-    /** Generator of VIEW classes. */
-    private ViewClassGenerator viewClassGenerator;
-
-    /** Generator of INIT classes. */
-    private InitClassGenerator initClassGenerator;
-
-    /** Generator of CHANGE classes. */
-    private ChangeClassGenerator changeClassGenerator;
-
     /** Class file writer. */
     private Filer filer;
 
@@ -135,9 +105,6 @@ public class Processor extends AbstractProcessor {
         super.init(processingEnv);
 
         filer = processingEnv.getFiler();
-        viewClassGenerator = new ViewClassGenerator(processingEnv);
-        initClassGenerator = new InitClassGenerator(processingEnv);
-        changeClassGenerator = new ChangeClassGenerator(processingEnv);
     }
 
     /** {@inheritDoc} */
@@ -148,15 +115,11 @@ public class Processor extends AbstractProcessor {
 
         List<ConfigurationDescription> roots = new ArrayList<>();
 
-        // Package to use for Selectors and Keys classes
-        String packageForUtil = "";
-
         // All classes annotated with @Config
         final List<TypeElement> annotatedConfigs = roundEnvironment
             .getElementsAnnotatedWithAny(Set.of(ConfigurationRoot.class, Config.class)).stream()
             .filter(element -> element.getKind() == ElementKind.CLASS)
             .map(TypeElement.class::cast)
-            .sorted(Comparator.comparing((TypeElement element) -> element.getQualifiedName().toString()).reversed())
             .collect(Collectors.toList());
 
         if (annotatedConfigs.isEmpty())
@@ -195,10 +158,8 @@ public class Processor extends AbstractProcessor {
             );
 
             // If root, then use it's package as package for Selectors and Keys
-            if (isRoot) {
+            if (isRoot)
                 roots.add(configDesc);
-                packageForUtil = packageName;
-            }
 
             TypeSpec.Builder configurationClassBuilder = TypeSpec.classBuilder(configClass)
                 .addSuperinterface(configInterface)
@@ -208,7 +169,6 @@ public class Processor extends AbstractProcessor {
                 .addModifiers(PUBLIC);
 
             CodeBlock.Builder constructorBodyBuilder = CodeBlock.builder();
-            CodeBlock.Builder copyConstructorBodyBuilder = CodeBlock.builder();
 
             for (VariableElement field : fields) {
                 Element fieldTypeElement = processingEnv.getTypeUtils().asElement(field.asType());
@@ -244,10 +204,7 @@ public class Processor extends AbstractProcessor {
                     configurationClassBuilder.addField(nestedConfigField);
 
                     // Constructor statement
-                    constructorBodyBuilder.addStatement("add($L = new $T(qualifiedName, $S, false, configurator, this.root))", fieldName, getMethodType, fieldName);
-
-                    // Copy constructor statement
-                    copyConstructorBodyBuilder.addStatement("add($L = base.$L.copy(this.root))", fieldName, fieldName);
+                    constructorBodyBuilder.addStatement("add($L = new $T(keys, $S, rootKey, changer))", fieldName, getMethodType, fieldName);
                 }
 
                 final NamedConfigValue namedConfigAnnotation = field.getAnnotation(NamedConfigValue.class);
@@ -273,15 +230,12 @@ public class Processor extends AbstractProcessor {
 
                     // Constructor statement
                     constructorBodyBuilder.addStatement(
-                        "add($L = new $T(qualifiedName, $S, configurator, this.root, (p, k) -> new $T(p, k, true, configurator, this.root)))",
+                        "add($L = new $T(keys, $S, rootKey, changer, (p, k) -> new $T(p, k, rootKey, changer)))",
                         fieldName,
                         getMethodType,
                         fieldName,
                         fieldType
                     );
-
-                    // Copy constructor statement
-                    copyConstructorBodyBuilder.addStatement("add($L = base.$L.copy(this.root))", fieldName, fieldName);
                 }
 
                 final Value valueAnnotation = field.getAnnotation(Value.class);
@@ -304,23 +258,20 @@ public class Processor extends AbstractProcessor {
 
                     // Constructor statement
                     constructorBodyBuilder.addStatement(
-                        "add($L = new $T(qualifiedName, $S, new $T($T.class, $S), this.configurator, this.root), $L)",
-                        fieldName, getMethodType, fieldName, MemberKey.class, configClass, fieldName, validatorsBlock
+                        "add($L = new $T(keys, $S, rootKey, changer), $L)",
+                        fieldName, getMethodType, fieldName, validatorsBlock
                     );
-
-                    // Copy constructor statement
-                    copyConstructorBodyBuilder.addStatement("add($L = base.$L.copy(this.root))", fieldName, fieldName);
                 }
 
                 configDesc.getFields().add(new ConfigurationElement(getMethodType, fieldName, viewClassType, initClassType, changeClassType));
 
-                createGettersAndSetter(configurationClassBuilder, configurationInterfaceBuilder, fieldName, types, valueAnnotation);
+                createGetters(configurationClassBuilder, configurationInterfaceBuilder, fieldName, types);
             }
 
             props.put(configClass, configDesc);
 
             // Create VIEW, INIT and CHANGE classes
-            createPojoBindings(packageName, fields, schemaClassName, configurationClassBuilder, configurationInterfaceBuilder);
+            createPojoBindings(fields, schemaClassName, configurationClassBuilder, configurationInterfaceBuilder);
 
             if (isRoot) {
                 TypeMirror storageType = null;
@@ -336,42 +287,14 @@ public class Processor extends AbstractProcessor {
             }
 
             // Create constructors for configuration class
-            createConstructors(configClass, configName, configurationClassBuilder, CONFIGURATOR_TYPE, constructorBodyBuilder, copyConstructorBodyBuilder);
-
-            // Create copy method for configuration class
-            createCopyMethod(configClass, configurationClassBuilder);
+            createConstructors(configurationClassBuilder, constructorBodyBuilder);
 
             // Write configuration interface
-            JavaFile interfaceFile = JavaFile.builder(packageName, configurationInterfaceBuilder.build()).build();
+            buildClass(packageName, configurationInterfaceBuilder.build());
 
-            try {
-                interfaceFile.writeTo(filer);
-            } catch (IOException e) {
-                throw new ProcessorException("Failed to create configuration class " + configClass.toString(), e);
-            }
-
-            // Write configuration
-            JavaFile classFile = JavaFile.builder(packageName, configurationClassBuilder.build()).build();
-
-            try {
-                classFile.writeTo(filer);
-            } catch (IOException e) {
-                throw new ProcessorException("Failed to create configuration class " + configClass.toString(), e);
-            }
+            buildClass(packageName, configurationClassBuilder.build());
         }
 
-        // Get all generated configuration nodes
-        final List<ConfigurationNode> flattenConfig = roots.stream()
-            .map((ConfigurationDescription cfg) -> buildConfigForest(cfg, props))
-            .flatMap(Set::stream)
-            .collect(Collectors.toList());
-
-        // Generate Keys class
-        createKeysClass(packageForUtil, flattenConfig);
-
-        // Generate Selectors class
-        createSelectorsClass(packageForUtil, flattenConfig);
-
         return true;
     }
 
@@ -384,34 +307,33 @@ public class Processor extends AbstractProcessor {
     ) {
         ParameterizedTypeName fieldTypeName = ParameterizedTypeName.get(ClassName.get(RootKey.class), configInterface);
 
-        ClassName nodeClassName = ClassName.get(
-            schemaClassName.packageName() + ".impl",
-            schemaClassName.simpleName().replace("ConfigurationSchema", "Node")
-        );
+        ClassName nodeClassName = Utils.getNodeName(schemaClassName);
 
         FieldSpec keyField = FieldSpec.builder(
             fieldTypeName, "KEY", PUBLIC, STATIC, FINAL)
-            .initializer("$T.newRootKey($S, $T.class, $T::new)", ConfigurationRegistry.class, configDesc.getName(), storageType, nodeClassName)
+            .initializer(
+                "$T.newRootKey($S, $T.class, $T::new, (rootKey, changer) -> new $T($T.emptyList(), $S, rootKey, changer))",
+                ConfigurationRegistry.class, configDesc.getName(), storageType, nodeClassName,
+                Utils.getConfigurationName(schemaClassName), Collections.class, configDesc.getName()
+            )
             .build();
 
         configurationClassBuilder.addField(keyField);
     }
 
     /**
-     * Create getters and setters for configuration class.
+     * Create getters for configuration class.
      *
      * @param configurationClassBuilder
      * @param configurationInterfaceBuilder
      * @param fieldName
      * @param types
-     * @param valueAnnotation
      */
-    private void createGettersAndSetter(
+    private void createGetters(
         TypeSpec.Builder configurationClassBuilder,
         TypeSpec.Builder configurationInterfaceBuilder,
         String fieldName,
-        ConfigurationFieldTypes types,
-        Value valueAnnotation
+        ConfigurationFieldTypes types
     ) {
         MethodSpec interfaceGetMethod = MethodSpec.methodBuilder(fieldName)
             .addModifiers(PUBLIC, ABSTRACT)
@@ -420,21 +342,13 @@ public class Processor extends AbstractProcessor {
         configurationInterfaceBuilder.addMethod(interfaceGetMethod);
 
         MethodSpec getMethod = MethodSpec.methodBuilder(fieldName)
+            .addAnnotation(Override.class)
+            .addJavadoc("{@inheritDoc}")
             .addModifiers(PUBLIC, FINAL)
             .returns(types.getGetMethodType())
             .addStatement("return $L", fieldName)
             .build();
         configurationClassBuilder.addMethod(getMethod);
-
-        if (valueAnnotation != null) {
-            MethodSpec setMethod = MethodSpec
-                .methodBuilder(fieldName)
-                .addModifiers(PUBLIC, FINAL)
-                .addParameter(types.getUnwrappedType(), fieldName)
-                .addStatement("this.$L.change($L)", fieldName, fieldName)
-                .build();
-            configurationClassBuilder.addMethod(setMethod);
-        }
     }
 
     /**
@@ -467,13 +381,15 @@ public class Processor extends AbstractProcessor {
         final NamedConfigValue namedConfigAnnotation = field.getAnnotation(NamedConfigValue.class);
         if (namedConfigAnnotation != null) {
             ClassName fieldType = Utils.getConfigurationName((ClassName) baseType);
+            //TODO IGNITE-14182 This is BS, interface name must be used instead.
+            ClassName interfaceFieldType = Utils.getConfigurationName((ClassName) baseType);
 
             viewClassType = Utils.getViewName((ClassName) baseType);
             initClassType = Utils.getInitName((ClassName) baseType);
             changeClassType = Utils.getChangeName((ClassName) baseType);
 
             getMethodType = ParameterizedTypeName.get(ClassName.get(NamedListConfiguration.class), viewClassType, fieldType, initClassType, changeClassType);
-            interfaceGetMethodType = ParameterizedTypeName.get(ClassName.get(NamedListConfiguration.class), viewClassType, fieldType, initClassType, changeClassType);
+            interfaceGetMethodType = ParameterizedTypeName.get(ClassName.get(NamedListConfiguration.class), viewClassType, interfaceFieldType, initClassType, changeClassType);
         }
 
         final Value valueAnnotation = field.getAnnotation(Value.class);
@@ -557,234 +473,36 @@ public class Processor extends AbstractProcessor {
     }
 
     /**
-     * Create copy-method for configuration class.
-     *
-     * @param configClass Configuration class name.
-     * @param configurationClassBuilder Configuration class builder.
-     */
-    private void createCopyMethod(ClassName configClass, TypeSpec.Builder configurationClassBuilder) {
-        MethodSpec copyMethod = MethodSpec.methodBuilder("copy")
-            .addAnnotation(Override.class)
-            .addModifiers(PUBLIC)
-            .addParameter(DynamicConfiguration.class, "root")
-            .returns(configClass)
-            .addStatement("return new $T(this, root)", configClass)
-            .build();
-
-        configurationClassBuilder.addMethod(copyMethod);
-    }
-
-    /**
      * Create configuration class constructors.
      *
-     * @param configClass Configuration class name.
-     * @param configName Configuration name.
-     * @param configurationClassBuilder Configuration class builder.
      * @param configuratorClassName Configurator (configuration wrapper) class name.
-     * @param constructorBodyBuilder Constructor body.
      * @param copyConstructorBodyBuilder Copy constructor body.
+     * @param configurationClassBuilder Configuration class builder.
+     * @param constructorBodyBuilder Constructor body.
      */
     private void createConstructors(
-        ClassName configClass,
-        String configName,
         TypeSpec.Builder configurationClassBuilder,
-        ParameterizedTypeName configuratorClassName,
-        CodeBlock.Builder constructorBodyBuilder,
-        CodeBlock.Builder copyConstructorBodyBuilder
+        CodeBlock.Builder constructorBodyBuilder
     ) {
         final MethodSpec constructorWithName = MethodSpec.constructorBuilder()
             .addModifiers(PUBLIC)
-            .addParameter(String.class, "prefix")
+            .addParameter(ParameterizedTypeName.get(List.class, String.class), "prefix")
             .addParameter(String.class, "key")
-            .addParameter(boolean.class, "isNamed")
-            .addParameter(configuratorClassName, "configurator")
-            .addParameter(DynamicConfiguration.class, "root")
-            .addStatement("super(prefix, key, isNamed, configurator, root)")
+            .addParameter(ParameterizedTypeName.get(ClassName.get(RootKey.class), WILDCARD), "rootKey")
+            .addParameter(ConfigurationChanger.class, "changer")
+            .addStatement("super(prefix, key, rootKey, changer)")
             .addCode(constructorBodyBuilder.build())
             .build();
         configurationClassBuilder.addMethod(constructorWithName);
-
-        final MethodSpec copyConstructor = MethodSpec.constructorBuilder()
-            .addModifiers(PRIVATE)
-            .addParameter(configClass, "base")
-            .addParameter(DynamicConfiguration.class, "root")
-            .addStatement("super(base.prefix, base.key, base.isNamed, base.configurator, root)")
-            .addCode(copyConstructorBodyBuilder.build())
-            .build();
-        configurationClassBuilder.addMethod(copyConstructor);
-
-        final MethodSpec emptyConstructor = MethodSpec.constructorBuilder()
-            .addModifiers(PUBLIC)
-            .addParameter(configuratorClassName, "configurator")
-            .addStatement("this($S, $S, false, configurator, null)", "", configName)
-            .build();
-
-        configurationClassBuilder.addMethod(emptyConstructor);
-    }
-
-    /**
-     * Create selectors.
-     *
-     * @param packageForUtil Package to place selectors class to.
-     * @param flattenConfig List of configuration nodes.
-     */
-    private void createSelectorsClass(String packageForUtil, List<ConfigurationNode> flattenConfig) {
-        ClassName selectorsClassName = ClassName.get(packageForUtil, "Selectors");
-
-        final TypeSpec.Builder selectorsClass = TypeSpec.classBuilder(selectorsClassName)
-            .superclass(BaseSelectors.class)
-            .addModifiers(PUBLIC, FINAL);
-
-        final CodeBlock.Builder selectorsStaticBlockBuilder = CodeBlock.builder();
-        selectorsStaticBlockBuilder.addStatement("$T publicLookup = $T.publicLookup()", MethodHandles.Lookup.class, MethodHandles.class);
-
-        selectorsStaticBlockBuilder.beginControlFlow("try");
-
-        // For every configuration node create selector (based on a method call chain)
-        for (ConfigurationNode configNode : flattenConfig) {
-            String regex = "([a-z])([A-Z]+)";
-            String replacement = "$1_$2";
-
-            // Selector variable name (like LOCAL_BASELINE_AUTO_ADJUST_ENABLED)
-            final String varName = configNode.getName()
-                .replaceAll(regex, replacement)
-                .toUpperCase()
-                .replace(".", "_");
-
-            TypeName type = configNode.getType();
-
-            if (Utils.isNamedConfiguration(type))
-                type = Utils.unwrapNamedListConfigurationClass(type);
-
-            StringBuilder methodCall = new StringBuilder();
-
-            ConfigurationNode current = configNode;
-            ConfigurationNode root = null;
-            int namedCount = 0;
-
-            // Walk from node up to the root and create a method call chain
-            while (current != null) {
-                boolean isNamed = false;
-
-                if (Utils.isNamedConfiguration(current.getType())) {
-                    namedCount++;
-                    isNamed = true;
-                }
-
-                if (current.getParent() != null) {
-                    String newMethodCall = "." + current.getOriginalName() + "()";
-                    // if config is named, then create a call with name parameter
-                    if (isNamed)
-                        newMethodCall += ".get(name" + (namedCount - 1) + ")";
-
-                    methodCall.insert(0, newMethodCall);
-                } else
-                    root = current;
-
-                current = current.getParent();
-            }
-
-            TypeName selectorRec = Utils.getParameterized(ClassName.get(Selector.class), root.getType(), type, configNode.getView(), configNode.getInit(), configNode.getChange());
-
-            if (namedCount > 0) {
-                final MethodSpec.Builder builder = MethodSpec.methodBuilder(varName);
-
-                for (int i = 0; i < namedCount; i++) {
-                    builder.addParameter(String.class, "name" + i);
-                }
-
-                selectorsClass.addMethod(
-                    builder
-                        .returns(selectorRec)
-                        .addModifiers(PUBLIC, STATIC, FINAL)
-                        .addStatement("return (root) -> root$L", methodCall.toString())
-                        .build()
-                );
-
-                // Build a list of parameters for statement
-                List<Object> params = new ArrayList<>();
-                params.add(MethodHandle.class);
-                params.add(varName);
-                params.add(selectorsClassName);
-                params.add(varName);
-                params.add(MethodType.class);
-                params.add(Selector.class);
-
-                // For every named config in call chain -- add String (name) parameter
-                for (int i = 0; i < namedCount; i++) {
-                    params.add(String.class);
-                }
-
-                // Create a string for name parameters
-                final String nameStringParameters = IntStream.range(0, namedCount).mapToObj(i -> "$T.class").collect(Collectors.joining(","));
-
-                selectorsStaticBlockBuilder.addStatement("$T $L = publicLookup.findStatic($T.class, $S, $T.methodType($T.class, " + nameStringParameters + "))", params.toArray());
-
-                selectorsStaticBlockBuilder.addStatement("put($S, $L)", configNode.getName(), varName);
-            }
-            else {
-                selectorsClass.addField(
-                    FieldSpec.builder(selectorRec, varName)
-                        .addModifiers(PUBLIC, STATIC, FINAL)
-                        .initializer("(root) -> root$L", methodCall.toString())
-                        .build()
-                );
-                selectorsStaticBlockBuilder.addStatement("put($S, $L)", configNode.getName(), varName);
-            }
-        }
-
-        selectorsStaticBlockBuilder
-            .nextControlFlow("catch ($T e)", Exception.class)
-            .endControlFlow();
-
-        selectorsClass.addStaticBlock(selectorsStaticBlockBuilder.build());
-
-        JavaFile selectorsClassFile = JavaFile.builder(selectorsClassName.packageName(), selectorsClass.build()).build();
-        try {
-            selectorsClassFile.writeTo(filer);
-        }
-        catch (IOException e) {
-            throw new ProcessorException("Failed to write class: " + e.getMessage(), e);
-        }
-    }
-
-    /**
-     * Create keys class.
-     *
-     * @param packageForUtil Package to place keys class to.
-     * @param flattenConfig List of configuration nodes.
-     */
-    private void createKeysClass(String packageForUtil, List<ConfigurationNode> flattenConfig) {
-        final TypeSpec.Builder keysClass = TypeSpec.classBuilder("Keys").addModifiers(PUBLIC, FINAL);
-
-        for (ConfigurationNode node : flattenConfig) {
-            final String varName = node.getName().toUpperCase().replace(".", "_");
-            keysClass.addField(
-                FieldSpec.builder(String.class, varName)
-                    .addModifiers(PUBLIC, STATIC, FINAL)
-                    .initializer("$S", node.getName())
-                    .build()
-            );
-        }
-
-        JavaFile keysClassFile = JavaFile.builder(packageForUtil, keysClass.build()).build();
-        try {
-            keysClassFile.writeTo(filer);
-        } catch (IOException e) {
-            throw new ProcessorException("Failed to write class: " + e.getMessage(), e);
-        }
     }
 
     /**
      * Create VIEW, INIT and CHANGE classes and methods.
-     *
-     * @param packageName Configuration package name.
      * @param fields List of configuration fields.
      * @param schemaClassName Class name of schema.
      * @param configurationClassBuilder Configuration class builder.
      */
     private void createPojoBindings(
-        String packageName,
         List<VariableElement> fields,
         ClassName schemaClassName,
         TypeSpec.Builder configurationClassBuilder,
@@ -804,55 +522,16 @@ public class Processor extends AbstractProcessor {
 
         configurationInterfaceBuilder.addSuperinterface(confTreeParameterized);
 
-        try {
-            viewClassGenerator.create(packageName, viewClassTypeName, fields);
-            final MethodSpec toViewMethod = createToViewMethod(viewClassTypeName, fields);
-            configurationClassBuilder.addMethod(toViewMethod);
-        }
-        catch (IOException e) {
-            throw new ProcessorException("Failed to write class " + viewClassTypeName.toString(), e);
-        }
-
-        try {
-            changeClassGenerator.create(packageName, changeClassName, fields);
-            final MethodSpec changeMethod = createChangeMethod(changeClassName, fields);
-            configurationClassBuilder.addMethod(changeMethod);
-        }
-        catch (IOException e) {
-            throw new ProcessorException("Failed to write class " + changeClassName.toString(), e);
-        }
-
-        try {
-            initClassGenerator.create(packageName, initClassName, fields);
-            final MethodSpec initMethod = createInitMethod(initClassName, fields);
-            configurationClassBuilder.addMethod(initMethod);
-        }
-        catch (IOException e) {
-            throw new ProcessorException("Failed to write class " + initClassName.toString(), e);
-        }
-
         // This code will be refactored in the future. Right now I don't want to entangle it with existing code
         // generation. It has only a few considerable problems - hardcode and a lack of proper arrays handling.
         // Clone method should be used to guarantee data integrity.
-        ClassName viewClsName = ClassName.get(
-            schemaClassName.packageName(),
-            schemaClassName.simpleName().replace("ConfigurationSchema", "View")
-        );
-
-        ClassName changeClsName = ClassName.get(
-            schemaClassName.packageName(),
-            schemaClassName.simpleName().replace("ConfigurationSchema", "Change")
-        );
-
-        ClassName initClsName = ClassName.get(
-            schemaClassName.packageName(),
-            schemaClassName.simpleName().replace("ConfigurationSchema", "Init")
-        );
-
-        ClassName nodeClsName = ClassName.get(
-            schemaClassName.packageName() + ".impl",
-            schemaClassName.simpleName().replace("ConfigurationSchema", "Node")
-        );
+        ClassName viewClsName = Utils.getViewName(schemaClassName);
+
+        ClassName changeClsName = Utils.getChangeName(schemaClassName);
+
+        ClassName initClsName = Utils.getInitName(schemaClassName);
+
+        ClassName nodeClsName = Utils.getNodeName(schemaClassName);
 
         TypeSpec.Builder viewClsBuilder = TypeSpec.interfaceBuilder(viewClsName)
             .addModifiers(PUBLIC);
@@ -1024,11 +703,10 @@ public class Processor extends AbstractProcessor {
 
                         if (!namedListField) {
                             nodeChangeMtdBuilder.addStatement(
-                                "$L = $L == null ? new $T() : $L",
+                                "if ($L == null) $L = new $T()",
                                 fieldName,
                                 fieldName,
-                                nodeFieldType,
-                                fieldName
+                                nodeFieldType
                             );
                             nodeChangeMtdBuilder.addStatement("$L.accept($L)", paramName, fieldName);
                         }
@@ -1089,11 +767,10 @@ public class Processor extends AbstractProcessor {
 
                         if (!namedListField) {
                             nodeInitMtdBuilder.addStatement(
-                                "$L = $L == null ? new $T() : $L",
+                                "if ($L == null) $L = new $T()",
                                 fieldName,
                                 fieldName,
-                                nodeFieldType,
-                                fieldName
+                                nodeFieldType
                             );
 
                             nodeInitMtdBuilder.addStatement("$L.accept($L)", paramName, fieldName);
@@ -1120,19 +797,19 @@ public class Processor extends AbstractProcessor {
                     traverseChildrenBuilder.addStatement("visitor.visitLeafNode($S, $L)", fieldName, fieldName);
 
                     traverseChildBuilder
-                        .addStatement("case $S: return visitor.visitLeafNode($S, $L)", fieldName, fieldName, fieldName);
+                        .addStatement("case $S: return visitor.visitLeafNode(key, $L)", fieldName, fieldName);
                 }
                 else if (namedListField) {
                     traverseChildrenBuilder.addStatement("visitor.visitNamedListNode($S, $L)", fieldName, fieldName);
 
                     traverseChildBuilder
-                        .addStatement("case $S: return visitor.visitNamedListNode($S, $L)", fieldName, fieldName, fieldName);
+                        .addStatement("case $S: return visitor.visitNamedListNode(key, $L)", fieldName, fieldName);
                 }
                 else {
                     traverseChildrenBuilder.addStatement("visitor.visitInnerNode($S, $L)", fieldName, fieldName);
 
                     traverseChildBuilder
-                        .addStatement("case $S: return visitor.visitInnerNode($S, $L)", fieldName, fieldName, fieldName);
+                        .addStatement("case $S: return visitor.visitInnerNode(key, $L)", fieldName, fieldName);
                 }
             }
 
@@ -1200,179 +877,31 @@ public class Processor extends AbstractProcessor {
         TypeSpec initCls = initClsBuilder.build();
         TypeSpec nodeCls = nodeClsBuilder.build();
 
+        buildClass(viewClsName.packageName(), viewCls);
+        buildClass(changeClsName.packageName(), changeCls);
+        buildClass(initClsName.packageName(), initCls);
+        buildClass(nodeClsName.packageName(), nodeCls);
+    }
+
+    /** */
+    private void buildClass(String packageName, TypeSpec cls) {
         try {
-            buildClass(viewClsName, viewCls);
-            buildClass(changeClsName, changeCls);
-            buildClass(initClsName, initCls);
-            buildClass(nodeClsName, nodeCls);
+            JavaFile.builder(packageName, cls)
+                .indent(INDENT)
+                .build()
+                .writeTo(filer);
         }
         catch (IOException e) {
-            throw new ProcessorException("Failed to generate classes", e);
+            throw new ProcessorException("Failed to generate class " + packageName + "." + cls.name, e);
         }
     }
 
     /** */
-    private void buildClass(ClassName viewClsName, TypeSpec viewCls) throws IOException {
-        JavaFile.builder(viewClsName.packageName(), viewCls)
-            .indent(INDENT)
-            .build()
-            .writeTo(filer);
-    }
-
-    /** */
     private static String capitalize(String name) {
         return name.substring(0, 1).toUpperCase() + name.substring(1);
     }
 
     /**
-     * Build configuration forest base on root configuration description and all processed configurations.
-     *
-     * @param root Root configuration description.
-     * @param props All configurations.
-     * @return All possible config trees.
-     */
-    private Set<ConfigurationNode> buildConfigForest(ConfigurationDescription root, Map<TypeName, ConfigurationDescription> props) {
-        Set<ConfigurationNode> res = new HashSet<>();
-        Deque<ConfigurationNode> propsStack = new LinkedList<>();
-
-        ConfigurationNode rootNode = new ConfigurationNode(root.getType(), root.getName(), root.getName(), root.getView(), root.getInit(), root.getChange(), null);
-
-        propsStack.addFirst(rootNode);
-
-        // Walk through the all fields of every node and build a tree of configuration (more like chain)
-        while (!propsStack.isEmpty()) {
-            final ConfigurationNode current = propsStack.pollFirst();
-
-            // Get configuration type
-            TypeName type = current.getType();
-
-            if (Utils.isNamedConfiguration(type))
-                type = Utils.unwrapNamedListConfigurationClass(current.getType());
-
-            final ConfigurationDescription configDesc = props.get(type);
-
-            // Get fields of configuration
-            final List<ConfigurationElement> propertiesList = configDesc.getFields();
-
-            if (current.getName() != null && !current.getName().isEmpty())
-                // Add current node to result
-                res.add(current);
-
-            for (ConfigurationElement property : propertiesList) {
-                String qualifiedName = property.getName();
-
-                if (current.getName() != null && !current.getName().isEmpty())
-                    qualifiedName = current.getName() + "." + qualifiedName;
-
-                final ConfigurationNode newChainElement = new ConfigurationNode(
-                    property.getType(),
-                    qualifiedName,
-                    property.getName(),
-                    property.getView(),
-                    property.getInit(),
-                    property.getChange(),
-                    current
-                );
-
-                boolean isNamedConfig = false;
-                if (property.getType() instanceof ParameterizedTypeName) {
-                    final ParameterizedTypeName parameterized = (ParameterizedTypeName) property.getType();
-
-                    if (parameterized.rawType.equals(ClassName.get(NamedListConfiguration.class)))
-                        isNamedConfig = true;
-                }
-
-                if (props.containsKey(property.getType()) || isNamedConfig)
-                    // If it's not a leaf, add to stack
-                    propsStack.add(newChainElement);
-                else
-                    // otherwise, add to result
-                    res.add(newChainElement);
-
-            }
-        }
-        return res;
-    }
-
-    /**
-     * Create {@link org.apache.ignite.configuration.ConfigurationProperty#value} method for configuration class.
-     *
-     * @param type VIEW method type.
-     * @param variables List of VIEW object's fields.
-     * @return toView() method.
-     */
-    public MethodSpec createToViewMethod(TypeName type, List<VariableElement> variables) {
-        String args = variables.stream()
-            .map(v -> v.getSimpleName().toString() + ".value()")
-            .collect(Collectors.joining(", "));
-
-        final CodeBlock returnBlock = CodeBlock.builder()
-            .add("return new $T($L)", type, args)
-            .build();
-
-        return MethodSpec.methodBuilder("value")
-            .addModifiers(PUBLIC)
-            .addAnnotation(Override.class)
-            .returns(type)
-            .addStatement(returnBlock)
-            .build();
-    }
-
-    /**
-     * Create {@link org.apache.ignite.configuration.internal.Modifier#init(Object)} method (accepts INIT object) for configuration class.
-     *
-     * @param type INIT method type.
-     * @param variables List of INIT object's fields.
-     * @return Init method.
-     */
-    public MethodSpec createInitMethod(TypeName type, List<VariableElement> variables) {
-        final CodeBlock.Builder builder = CodeBlock.builder();
-
-        for (VariableElement variable : variables) {
-            final String name = variable.getSimpleName().toString();
-            builder.beginControlFlow("if (initial.$L() != null)", name);
-            builder.addStatement("$L.init(initial.$L())", name, name);
-            builder.endControlFlow();
-        }
-
-        return MethodSpec.methodBuilder("init")
-            .addModifiers(PUBLIC)
-            .addAnnotation(Override.class)
-            .addParameter(type, "initial")
-            .addCode(builder.build())
-            .build();
-    }
-
-    /**
-     * Create {@link org.apache.ignite.configuration.internal.Modifier#change(Object)} method (accepts CHANGE object) for configuration class.
-     *
-     * @param type CHANGE method type.
-     * @param variables List of CHANGE object's fields.
-     * @return Change method.
-     */
-    public MethodSpec createChangeMethod(TypeName type, List<VariableElement> variables) {
-        final CodeBlock.Builder builder = CodeBlock.builder();
-
-        for (VariableElement variable : variables) {
-            final Value valueAnnotation = variable.getAnnotation(Value.class);
-            if (valueAnnotation != null && valueAnnotation.immutable())
-                continue;
-
-            final String name = variable.getSimpleName().toString();
-            builder.beginControlFlow("if (changes.$L() != null)", name);
-            builder.addStatement("$L.changeWithoutValidation(changes.$L())", name, name);
-            builder.endControlFlow();
-        }
-
-        return MethodSpec.methodBuilder("changeWithoutValidation")
-            .addModifiers(PUBLIC)
-            .addAnnotation(Override.class)
-            .addParameter(type, "changes")
-            .addCode(builder.build())
-            .build();
-    }
-
-    /**
      * Checks whether TypeName is a primitive (or String) or an array of primitives (or Strings)
      * @param typeName TypeName.
      * @return {@code true} if type is primitive or array.
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
index a1e3687..e08cf13 100644
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
+++ b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
@@ -142,6 +142,14 @@ public class Utils {
         );
     }
 
+    /** */
+    public static ClassName getNodeName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName() + ".impl",
+            schemaClassName.simpleName().replace("ConfigurationSchema", "Node")
+        );
+    }
+
     /**
      * Get {@link ClassName} for configuration VIEW object class.
      *
@@ -151,7 +159,7 @@ public class Utils {
     public static ClassName getViewName(ClassName schemaClassName) {
         return ClassName.get(
             schemaClassName.packageName(),
-            schemaClassName.simpleName().replace("ConfigurationSchema", "")
+            schemaClassName.simpleName().replace("ConfigurationSchema", "View")
         );
     }
 
@@ -164,7 +172,7 @@ public class Utils {
     public static ClassName getInitName(ClassName schemaClassName) {
         return ClassName.get(
             schemaClassName.packageName(),
-            "Init" + schemaClassName.simpleName().replace("ConfigurationSchema", "")
+            schemaClassName.simpleName().replace("ConfigurationSchema", "Init")
         );
     }
 
@@ -177,7 +185,7 @@ public class Utils {
     public static ClassName getChangeName(ClassName schemaClassName) {
         return ClassName.get(
             schemaClassName.packageName(),
-            "Change" + schemaClassName.simpleName().replace("ConfigurationSchema", "")
+            schemaClassName.simpleName().replace("ConfigurationSchema", "Change")
         );
     }
 
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ChangeClassGenerator.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ChangeClassGenerator.java
deleted file mode 100644
index 491485c..0000000
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ChangeClassGenerator.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal.pojo;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import org.apache.ignite.configuration.annotation.ConfigValue;
-import org.apache.ignite.configuration.annotation.NamedConfigValue;
-import org.apache.ignite.configuration.annotation.Value;
-import org.apache.ignite.configuration.internal.NamedList;
-import org.apache.ignite.configuration.processor.internal.Utils;
-
-/**
- * CHANGE object class generator.
- */
-public class ChangeClassGenerator extends ClassGenerator {
-    /** Constructor. */
-    public ChangeClassGenerator(ProcessingEnvironment env) {
-        super(env);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected FieldMapping mapField(VariableElement field) {
-        final ConfigValue configAnnotation = field.getAnnotation(ConfigValue.class);
-        final NamedConfigValue namedConfigAnnotation = field.getAnnotation(NamedConfigValue.class);
-        final Value valueAnnotation = field.getAnnotation(Value.class);
-
-        if (valueAnnotation != null && valueAnnotation.immutable())
-            return null;
-
-        final TypeMirror type = field.asType();
-        String name = field.getSimpleName().toString();
-
-        TypeName fieldType = TypeName.get(type);
-
-        if (fieldType.isPrimitive())
-            fieldType = fieldType.box();
-
-        if (namedConfigAnnotation != null || configAnnotation != null) {
-            ClassName confClass = (ClassName) fieldType;
-            fieldType = Utils.getChangeName(confClass);
-
-            if (namedConfigAnnotation != null)
-                fieldType = ParameterizedTypeName.get(ClassName.get(NamedList.class), fieldType);
-        }
-
-        final FieldSpec fieldSpec = FieldSpec.builder(fieldType, name, Modifier.PRIVATE).build();
-
-        return new FieldMapping(field, fieldSpec);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected MethodSpec mapMethod(ClassName clazz, FieldSpec field) {
-        final String name = field.name;
-        final String methodName = name.substring(0, 1).toUpperCase() + name.substring(1);
-        return MethodSpec.methodBuilder("with" + methodName)
-            .returns(clazz)
-            .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
-            .addParameter(field.type, name)
-            .addStatement("this.$L = $L", name, name)
-            .addStatement("return this")
-            .build();
-    }
-
-}
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ClassGenerator.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ClassGenerator.java
deleted file mode 100644
index 0ec13df..0000000
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ClassGenerator.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal.pojo;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.List;
-import java.util.Objects;
-import java.util.stream.Collectors;
-import javax.annotation.processing.Filer;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.VariableElement;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.JavaFile;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.TypeSpec;
-import org.apache.ignite.configuration.processor.internal.Utils;
-
-/**
- * Base POJO generator
- */
-public abstract class ClassGenerator {
-    /** Processing environment. */
-    protected final ProcessingEnvironment env;
-
-    /** Annotation processing filer. */
-    private final Filer filer;
-
-    /** Constructor. */
-    public ClassGenerator(ProcessingEnvironment env) {
-        this.env = env;
-        this.filer = env.getFiler();
-    }
-
-    /**
-     * Create class.
-     *
-     * @param packageName Package name for class.
-     * @param className Class name.
-     * @param fields List of fields.
-     * @throws IOException If failed to write class file.
-     */
-    public final void create(String packageName, ClassName className, List<VariableElement> fields) throws IOException {
-        TypeSpec.Builder classBuilder = TypeSpec
-            .classBuilder(className)
-            .addSuperinterface(Serializable.class)
-            .addModifiers(Modifier.PUBLIC, Modifier.FINAL);
-
-        List<FieldMapping> fieldMappings = fields.stream().map(this::mapField).filter(Objects::nonNull).collect(Collectors.toList());
-
-        generate(classBuilder, packageName, className, fieldMappings);
-
-        final TypeSpec viewClass = classBuilder.build();
-        JavaFile classFile = JavaFile.builder(packageName, viewClass).build();
-        classFile.writeTo(filer);
-    }
-
-    /**
-     * Generate class fields, methods and constructor.
-     *
-     * @param classBuilder Class builder.
-     * @param packageName Package name.
-     * @param className Class name.
-     * @param fieldMappings Fields' mappings.
-     */
-    protected void generate(TypeSpec.Builder classBuilder, String packageName, ClassName className, List<FieldMapping> fieldMappings) {
-        List<FieldSpec> fieldSpecs = fieldMappings.stream().map(FieldMapping::getFieldSpec).collect(Collectors.toList());
-
-        List<MethodSpec> methodSpecs = fieldSpecs.stream().map(field -> mapMethod(className, field)).filter(Objects::nonNull).collect(Collectors.toList());
-
-        classBuilder.addFields(fieldSpecs);
-        classBuilder.addMethods(methodSpecs);
-
-        final MethodSpec constructor = createConstructor(fieldSpecs);
-        if (constructor != null)
-            classBuilder.addMethod(constructor);
-
-        final List<MethodSpec> getters = Utils.createGetters(fieldSpecs);
-
-        classBuilder.addMethods(getters);
-    }
-
-    /**
-     * Create {@link FieldSpec} from {@link VariableElement}.
-     *
-     * @param field Configuration class field.
-     * @return Mapping.
-     */
-    protected abstract FieldMapping mapField(VariableElement field);
-
-    /**
-     * Create access methods for field.
-     *
-     * @param clazz Method return type.
-     * @param field Configuration class field.
-     * @return Method specs.
-     */
-    protected abstract MethodSpec mapMethod(ClassName clazz, FieldSpec field);
-
-    /**
-     * Create constructor from fields.
-     *
-     * @param fields Configuration fields.
-     * @return If null, constructor won't be created.
-     */
-    protected MethodSpec createConstructor(List<FieldSpec> fields) {
-        return null;
-    }
-
-}
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/FieldMapping.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/FieldMapping.java
deleted file mode 100644
index c0b216e..0000000
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/FieldMapping.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal.pojo;
-
-import javax.lang.model.element.VariableElement;
-import com.squareup.javapoet.FieldSpec;
-
-/**
- * Mapping from {@link VariableElement} to {@link FieldSpec}
- */
-public class FieldMapping {
-    /** Variable element. */
-    private final VariableElement variableElement;
-
-    /** Field spec. */
-    private final FieldSpec fieldSpec;
-
-    /** Constructor. */
-    public FieldMapping(VariableElement variableElement, FieldSpec fieldSpec) {
-        this.variableElement = variableElement;
-        this.fieldSpec = fieldSpec;
-    }
-
-    /**
-     * Get varaible element.
-     */
-    public VariableElement getVariableElement() {
-        return variableElement;
-    }
-
-    /**
-     * Get field spec.
-     */
-    public FieldSpec getFieldSpec() {
-        return fieldSpec;
-    }
-}
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/InitClassGenerator.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/InitClassGenerator.java
deleted file mode 100644
index 6f5e784..0000000
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/InitClassGenerator.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal.pojo;
-
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import org.apache.ignite.configuration.annotation.ConfigValue;
-import org.apache.ignite.configuration.annotation.NamedConfigValue;
-import org.apache.ignite.configuration.internal.NamedList;
-import org.apache.ignite.configuration.processor.internal.Utils;
-
-/**
- * INIT object class generator.
- */
-public class InitClassGenerator extends ClassGenerator {
-    /** Constructor. */
-    public InitClassGenerator(ProcessingEnvironment env) {
-        super(env);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected FieldMapping mapField(VariableElement field) {
-        final ConfigValue configAnnotation = field.getAnnotation(ConfigValue.class);
-        final NamedConfigValue namedConfigAnnotation = field.getAnnotation(NamedConfigValue.class);
-
-        final TypeMirror type = field.asType();
-        String name = field.getSimpleName().toString();
-
-        TypeName fieldType = TypeName.get(type);
-
-        if (fieldType.isPrimitive())
-            fieldType = fieldType.box();
-
-        if (namedConfigAnnotation != null || configAnnotation != null) {
-            ClassName confClass = (ClassName) fieldType;
-            fieldType = Utils.getInitName(confClass);
-            
-            if (namedConfigAnnotation != null)
-                fieldType = ParameterizedTypeName.get(ClassName.get(NamedList.class), fieldType);
-
-        }
-
-        final FieldSpec fieldSpec = FieldSpec.builder(fieldType, name, Modifier.PRIVATE).build();
-
-        return new FieldMapping(field, fieldSpec);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected MethodSpec mapMethod(ClassName clazz, FieldSpec field) {
-        final String name = field.name;
-        final String methodName = name.substring(0, 1).toUpperCase() + name.substring(1);
-        return MethodSpec.methodBuilder("with" + methodName)
-            .returns(clazz)
-            .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
-            .addParameter(field.type, name)
-            .addStatement("this.$L = $L", name, name)
-            .addStatement("return this")
-            .build();
-    }
-
-}
diff --git a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ViewClassGenerator.java b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ViewClassGenerator.java
deleted file mode 100644
index a192a04..0000000
--- a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/pojo/ViewClassGenerator.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.processor.internal.pojo;
-
-import java.util.List;
-import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.Modifier;
-import javax.lang.model.element.VariableElement;
-import javax.lang.model.type.TypeMirror;
-import com.squareup.javapoet.ClassName;
-import com.squareup.javapoet.FieldSpec;
-import com.squareup.javapoet.MethodSpec;
-import com.squareup.javapoet.ParameterizedTypeName;
-import com.squareup.javapoet.TypeName;
-import org.apache.ignite.configuration.annotation.ConfigValue;
-import org.apache.ignite.configuration.annotation.NamedConfigValue;
-import org.apache.ignite.configuration.internal.NamedList;
-import org.apache.ignite.configuration.processor.internal.Utils;
-
-/**
- * VIEW object class generator.
- */
-public class ViewClassGenerator extends ClassGenerator {
-    /** Constructor. */
-    public ViewClassGenerator(ProcessingEnvironment env) {
-        super(env);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected FieldMapping mapField(VariableElement field) {
-        final ConfigValue configAnnotation = field.getAnnotation(ConfigValue.class);
-        final NamedConfigValue namedConfigAnnotation = field.getAnnotation(NamedConfigValue.class);
-
-        final TypeMirror type = field.asType();
-        String name = field.getSimpleName().toString();
-
-        TypeName fieldType = TypeName.get(type);
-
-        if (fieldType.isPrimitive())
-            fieldType = fieldType.box();
-
-        if (namedConfigAnnotation != null || configAnnotation != null) {
-            ClassName confClass = (ClassName) fieldType;
-            fieldType = Utils.getViewName(confClass);
-
-            if (namedConfigAnnotation != null)
-                fieldType = ParameterizedTypeName.get(ClassName.get(NamedList.class), fieldType);
-        }
-
-        final FieldSpec fieldSpec = FieldSpec.builder(fieldType, name, Modifier.PRIVATE, Modifier.FINAL).build();
-
-        return new FieldMapping(field, fieldSpec);
-    }
-
-    /** {@inheritDoc} */
-    @Override protected MethodSpec mapMethod(ClassName clazz, FieldSpec field) {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override protected MethodSpec createConstructor(List<FieldSpec> fields) {
-        return Utils.createConstructor(fields);
-    }
-}
diff --git a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/LocalConfigurationSchema.java b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/LocalConfigurationSchema.java
index 2d565e4..8f091fb 100644
--- a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/LocalConfigurationSchema.java
+++ b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/LocalConfigurationSchema.java
@@ -19,11 +19,12 @@ package org.apache.ignite.configuration.sample;
 
 import org.apache.ignite.configuration.annotation.ConfigValue;
 import org.apache.ignite.configuration.annotation.ConfigurationRoot;
+import org.apache.ignite.configuration.sample.storage.TestConfigurationStorage;
 
 /**
  * Test local configuration schema.
  */
-@ConfigurationRoot(rootName = "local")
+@ConfigurationRoot(rootName = "local", storage = TestConfigurationStorage.class)
 public class LocalConfigurationSchema {
     /** Baseline. */
     @ConfigValue
diff --git a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/NetworkConfigurationSchema.java b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/NetworkConfigurationSchema.java
index f2facb6..bcb104d 100644
--- a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/NetworkConfigurationSchema.java
+++ b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/NetworkConfigurationSchema.java
@@ -19,11 +19,12 @@ package org.apache.ignite.configuration.sample;
 
 import org.apache.ignite.configuration.annotation.ConfigValue;
 import org.apache.ignite.configuration.annotation.ConfigurationRoot;
+import org.apache.ignite.configuration.sample.storage.TestConfigurationStorage;
 
 /**
  * Test network configuration schema.
  */
-@ConfigurationRoot(rootName = "network")
+@ConfigurationRoot(rootName = "network", storage = TestConfigurationStorage.class)
 public class NetworkConfigurationSchema {
     /** Discovery. */
     @ConfigValue
diff --git a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/UsageTest.java b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/UsageTest.java
index 89ee565..ba6dcd2 100644
--- a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/UsageTest.java
+++ b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/UsageTest.java
@@ -17,15 +17,14 @@
 
 package org.apache.ignite.configuration.sample;
 
-import java.util.Collections;
 import org.apache.ignite.configuration.ConfigurationRegistry;
-import org.apache.ignite.configuration.Configurator;
-import org.apache.ignite.configuration.internal.NamedList;
-import org.apache.ignite.configuration.validation.ConfigurationValidationException;
-import org.junit.jupiter.api.Assertions;
+import org.apache.ignite.configuration.sample.storage.TestConfigurationStorage;
 import org.junit.jupiter.api.Test;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Simple usage test of generated configuration schema.
@@ -35,74 +34,88 @@ public class UsageTest {
      * Test creation of configuration and calling configuration API methods.
      */
     @Test
-    public void test() {
-        InitLocal initLocal = new InitLocal().withBaseline(
-            new InitBaseline()
-                .withNodes(
-                    new NamedList<>(
-                        Collections.singletonMap("node1", new InitNode().withConsistentId("test").withPort(1000))
+    public void test() throws Exception {
+        var registry = new ConfigurationRegistry();
+
+        registry.registerRootKey(LocalConfiguration.KEY);
+
+        registry.registerStorage(new TestConfigurationStorage());
+
+        LocalConfiguration root = registry.getConfiguration(LocalConfiguration.KEY);
+
+        root.change(local ->
+            local.changeBaseline(baseline ->
+                baseline.changeNodes(nodes ->
+                    nodes.create("node1", node ->
+                        node.initConsistentId("test").initPort(1000)
                     )
+                ).changeAutoAdjust(autoAdjust ->
+                    autoAdjust.changeEnabled(true).changeTimeout(100_000L)
                 )
-                .withAutoAdjust(new InitAutoAdjust().withEnabled(true).withTimeout(100000L))
-        );
+            )
+        ).get(1, SECONDS);
+        assertTrue(root.baseline().autoAdjust().enabled().value());
 
-        final Configurator<LocalConfigurationImpl> configurator = Configurator.create(
-            LocalConfigurationImpl::new,
-            initLocal
-        );
+        root.baseline().autoAdjust().enabled().update(false).get(1, SECONDS);
 
-        final LocalConfiguration root = configurator.getRoot();
-        root.baseline().autoAdjust().enabled().value();
+        assertFalse(root.value().baseline().autoAdjust().enabled());
+        assertFalse(root.baseline().value().autoAdjust().enabled());
+        assertFalse(root.baseline().autoAdjust().value().enabled());
+        assertFalse(root.baseline().autoAdjust().enabled().value());
 
-        Assertions.assertThrows(ConfigurationValidationException.class, () -> {
-            configurator.set(Selectors.LOCAL_BASELINE_AUTO_ADJUST_ENABLED, false);
-        });
-        configurator.set(Selectors.LOCAL_BASELINE_AUTO_ADJUST, new ChangeAutoAdjust().withEnabled(false).withTimeout(0L));
-        configurator.getRoot().baseline().nodes().get("node1").autoAdjustEnabled(false);
-        configurator.getRoot().baseline().autoAdjust().enabled(true);
-        configurator.getRoot().baseline().nodes().get("node1").autoAdjustEnabled(true);
+        root.baseline().nodes().get("node1").autoAdjustEnabled().update(true).get(1, SECONDS);
 
-        Assertions.assertThrows(ConfigurationValidationException.class, () -> {
-            configurator.getRoot().baseline().autoAdjust().enabled(false);
-        });
+        assertTrue(root.value().baseline().nodes().get("node1").autoAdjustEnabled());
+        assertTrue(root.baseline().value().nodes().get("node1").autoAdjustEnabled());
+        assertTrue(root.baseline().nodes().value().get("node1").autoAdjustEnabled());
+        assertTrue(root.baseline().nodes().get("node1").value().autoAdjustEnabled());
+        assertTrue(root.baseline().nodes().get("node1").autoAdjustEnabled().value());
+
+        root.baseline().nodes().get("node1").change(node -> node.changeAutoAdjustEnabled(false)).get(1, SECONDS);
+        assertFalse(root.value().baseline().nodes().get("node1").autoAdjustEnabled());
     }
 
     /**
      * Test to show an API to work with multiroot configurations.
      */
     @Test
-    public void multiRootConfigurationTest() {
-        ConfigurationRegistry sysConf = new ConfigurationRegistry();
-
+    public void multiRootConfiguration() throws Exception {
         int failureDetectionTimeout = 30_000;
         int joinTimeout = 10_000;
 
         long autoAdjustTimeout = 30_000L;
 
-        InitNetwork initNetwork = new InitNetwork().withDiscovery(
-            new InitDiscovery()
-                .withFailureDetectionTimeout(failureDetectionTimeout)
-                .withJoinTimeout(joinTimeout)
-        );
-
-        InitLocal initLocal = new InitLocal().withBaseline(
-            new InitBaseline().withAutoAdjust(
-                new InitAutoAdjust().withEnabled(true)
-                    .withTimeout(autoAdjustTimeout))
-        );
-
-        Configurator<LocalConfigurationImpl> localConf = Configurator.create(LocalConfigurationImpl::new, initLocal);
+        ConfigurationRegistry registry = new ConfigurationRegistry();
 
-        sysConf.registerConfigurator(localConf);
+        registry.registerRootKey(NetworkConfiguration.KEY);
+        registry.registerRootKey(LocalConfiguration.KEY);
 
-        Configurator<NetworkConfigurationImpl> networkConf = Configurator.create(NetworkConfigurationImpl::new, initNetwork);
+        registry.registerStorage(new TestConfigurationStorage());
 
-        sysConf.registerConfigurator(networkConf);
-
-        assertEquals(failureDetectionTimeout,
-            sysConf.getConfiguration(NetworkConfigurationImpl.KEY).discovery().failureDetectionTimeout().value());
+        registry.getConfiguration(LocalConfiguration.KEY).change(local ->
+            local.changeBaseline(baseline ->
+                baseline.changeAutoAdjust(autoAdjust ->
+                    autoAdjust.changeEnabled(true).changeTimeout(autoAdjustTimeout)
+                )
+            )
+        ).get(1, SECONDS);
+
+        registry.getConfiguration(NetworkConfiguration.KEY).change(network ->
+            network.changeDiscovery(discovery ->
+                discovery
+                    .changeFailureDetectionTimeout(failureDetectionTimeout)
+                    .changeJoinTimeout(joinTimeout)
+            )
+        ).get(1, SECONDS);
+
+        assertEquals(
+            failureDetectionTimeout,
+            registry.getConfiguration(NetworkConfigurationImpl.KEY).discovery().failureDetectionTimeout().value()
+        );
 
-        assertEquals(autoAdjustTimeout,
-            sysConf.getConfiguration(LocalConfigurationImpl.KEY).baseline().autoAdjust().timeout().value());
+        assertEquals(
+            autoAdjustTimeout,
+            registry.getConfiguration(LocalConfigurationImpl.KEY).baseline().autoAdjust().timeout().value()
+        );
     }
 }
diff --git a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/storage/ConfigurationChangerTest.java b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/storage/ConfigurationChangerTest.java
index 494fb67..60d4b0a 100644
--- a/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/storage/ConfigurationChangerTest.java
+++ b/modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/storage/ConfigurationChangerTest.java
@@ -34,6 +34,7 @@ import org.apache.ignite.configuration.validation.ValidationIssue;
 import org.junit.jupiter.api.Test;
 import org.mockito.Mockito;
 
+import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.apache.ignite.configuration.sample.storage.AConfiguration.KEY;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -89,12 +90,12 @@ public class ConfigurationChangerTest {
             .initChild(init -> init.initIntCfg(1).initStrCfg("1"))
             .initElements(change -> change.create("a", init -> init.initStrCfg("1")));
 
-        final ConfigurationChanger changer = new ConfigurationChanger(storage);
-        changer.init(KEY);
+        final ConfigurationChanger changer = new ConfigurationChanger(KEY);
+        changer.init(storage);
 
         changer.registerConfiguration(KEY, configurator);
 
-        changer.change(Collections.singletonMap(KEY, data)).get();
+        changer.change(Collections.singletonMap(KEY, data)).get(1, SECONDS);
 
         ANode newRoot = (ANode)changer.getRootNode(KEY);
 
@@ -124,17 +125,17 @@ public class ConfigurationChangerTest {
                 .create("b", init -> init.initStrCfg("2"))
             );
 
-        final ConfigurationChanger changer1 = new ConfigurationChanger(storage);
-        changer1.init(KEY);
+        final ConfigurationChanger changer1 = new ConfigurationChanger(KEY);
+        changer1.init(storage);
 
-        final ConfigurationChanger changer2 = new ConfigurationChanger(storage);
-        changer2.init(KEY);
+        final ConfigurationChanger changer2 = new ConfigurationChanger(KEY);
+        changer2.init(storage);
 
         changer1.registerConfiguration(KEY, configurator);
         changer2.registerConfiguration(KEY, configurator);
 
-        changer1.change(Collections.singletonMap(KEY, data1)).get();
-        changer2.change(Collections.singletonMap(KEY, data2)).get();
+        changer1.change(Collections.singletonMap(KEY, data1)).get(1, SECONDS);
+        changer2.change(Collections.singletonMap(KEY, data2)).get(1, SECONDS);
 
         ANode newRoot1 = (ANode)changer1.getRootNode(KEY);
 
@@ -172,20 +173,20 @@ public class ConfigurationChangerTest {
                 .create("b", init -> init.initStrCfg("2"))
             );
 
-        final ConfigurationChanger changer1 = new ConfigurationChanger(storage);
-        changer1.init(KEY);
+        final ConfigurationChanger changer1 = new ConfigurationChanger(KEY);
+        changer1.init(storage);
 
-        final ConfigurationChanger changer2 = new ConfigurationChanger(storage);
-        changer2.init(KEY);
+        final ConfigurationChanger changer2 = new ConfigurationChanger(KEY);
+        changer2.init(storage);
 
         changer1.registerConfiguration(KEY, configurator);
         changer2.registerConfiguration(KEY, configurator);
 
-        changer1.change(Collections.singletonMap(KEY, data1)).get();
+        changer1.change(Collections.singletonMap(KEY, data1)).get(1, SECONDS);
 
         configuratorController.hasIssues(true);
 
-        assertThrows(ExecutionException.class, () -> changer2.change(Collections.singletonMap(KEY, data2)).get());
+        assertThrows(ExecutionException.class, () -> changer2.change(Collections.singletonMap(KEY, data2)).get(1, SECONDS));
 
         ANode newRoot = (ANode)changer2.getRootNode(KEY);
 
@@ -206,21 +207,21 @@ public class ConfigurationChangerTest {
 
         ANode data = new ANode().initChild(child -> child.initIntCfg(1));
 
-        final ConfigurationChanger changer = new ConfigurationChanger(storage);
+        final ConfigurationChanger changer = new ConfigurationChanger(KEY);
 
         storage.fail(true);
 
-        assertThrows(ConfigurationChangeException.class, () -> changer.init(KEY));
+        assertThrows(ConfigurationChangeException.class, () -> changer.init(storage));
 
         storage.fail(false);
 
-        changer.init(KEY);
+        changer.init(storage);
 
         changer.registerConfiguration(KEY, configurator);
 
         storage.fail(true);
 
-        assertThrows(ExecutionException.class, () -> changer.change(Collections.singletonMap(KEY, data)).get());
+        assertThrows(ExecutionException.class, () -> changer.change(Collections.singletonMap(KEY, data)).get(1, SECONDS));
 
         storage.fail(false);
 
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java
index fa156cb..1ee2d04 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java
@@ -18,6 +18,7 @@ package org.apache.ignite.configuration;
 
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -50,6 +51,9 @@ public class ConfigurationChanger {
     @Deprecated
     private final Map<RootKey<?>, Configurator<?>> configurators = new HashMap<>();
 
+    /** */
+    private final Set<RootKey<?>> rootKeys = new HashSet<>();
+
     /** Map that has all the trees in accordance to their storages. */
     private final Map<Class<? extends ConfigurationStorage>, StorageRoots> storagesRootsMap = new ConcurrentHashMap<>();
 
@@ -74,63 +78,63 @@ public class ConfigurationChanger {
     private final Map<Class<? extends ConfigurationStorage>, ConfigurationStorage> storageInstances = new HashMap<>();
 
     /** Constructor. */
-    public ConfigurationChanger(ConfigurationStorage... configurationStorages) {
-        for (ConfigurationStorage storage : configurationStorages)
-            storageInstances.put(storage.getClass(), storage);
+    public ConfigurationChanger(RootKey<?>... rootKeys) {
+        this.rootKeys.addAll(Arrays.asList(rootKeys));
+    }
+
+    /** */
+    public void addRootKey(RootKey<?> rootKey) {
+        assert !storageInstances.containsKey(rootKey.getStorageType());
+
+        rootKeys.add(rootKey);
     }
 
     /**
      * Initialize changer.
      */
     // ConfigurationChangeException, really?
-    public void init(RootKey<?>... rootKeys) throws ConfigurationChangeException {
-        Map<Class<? extends ConfigurationStorage>, Set<RootKey<?>>> rootsByStorage = new HashMap<>();
-
-        for (RootKey<?> rootKey : rootKeys) {
-            Class<? extends ConfigurationStorage> storageType = rootKey.getStorageType();
+    public void init(ConfigurationStorage configurationStorage) throws ConfigurationChangeException {
+        storageInstances.put(configurationStorage.getClass(), configurationStorage);
 
-            rootsByStorage.computeIfAbsent(storageType, c -> new HashSet<>()).add(rootKey);
-        }
+        Set<RootKey<?>> storageRootKeys = rootKeys.stream().filter(
+            rootKey -> configurationStorage.getClass() == rootKey.getStorageType()
+        ).collect(Collectors.toSet());
 
-        for (ConfigurationStorage configurationStorage : storageInstances.values()) {
-            Data data;
+        Data data;
 
-            try {
-                data = configurationStorage.readAll();
-            }
-            catch (StorageException e) {
-                throw new ConfigurationChangeException("Failed to initialize configuration: " + e.getMessage(), e);
-            }
+        try {
+            data = configurationStorage.readAll();
+        }
+        catch (StorageException e) {
+            throw new ConfigurationChangeException("Failed to initialize configuration: " + e.getMessage(), e);
+        }
 
-            Map<RootKey<?>, InnerNode> storageRootsMap = new HashMap<>();
+        Map<RootKey<?>, InnerNode> storageRootsMap = new HashMap<>();
 
-            Map<String, ?> dataValuesPrefixMap = ConfigurationUtil.toPrefixMap(data.values());
+        Map<String, ?> dataValuesPrefixMap = ConfigurationUtil.toPrefixMap(data.values());
 
-            for (RootKey<?> rootKey : rootsByStorage.get(configurationStorage.getClass())) {
-                Map<String, ?> rootPrefixMap = (Map<String, ?>)dataValuesPrefixMap.get(rootKey.key());
+        for (RootKey<?> rootKey : storageRootKeys) {
+            Map<String, ?> rootPrefixMap = (Map<String, ?>)dataValuesPrefixMap.get(rootKey.key());
 
-                if (rootPrefixMap == null) {
-                    //TODO IGNITE-14193 Init with defaults.
-                    storageRootsMap.put(rootKey, rootKey.createRootNode());
-                }
-                else {
-                    InnerNode rootNode = rootKey.createRootNode();
+            if (rootPrefixMap == null) {
+                //TODO IGNITE-14193 Init with defaults.
+                storageRootsMap.put(rootKey, rootKey.createRootNode());
+            }
+            else {
+                InnerNode rootNode = rootKey.createRootNode();
 
-                    ConfigurationUtil.fillFromPrefixMap(rootNode, rootPrefixMap);
+                ConfigurationUtil.fillFromPrefixMap(rootNode, rootPrefixMap);
 
-                    storageRootsMap.put(rootKey, rootNode);
-                }
+                storageRootsMap.put(rootKey, rootNode);
             }
+        }
 
-            storagesRootsMap.put(configurationStorage.getClass(), new StorageRoots(storageRootsMap, data.version()));
-
-            configurationStorage.addListener(changedEntries -> updateFromListener(
-                configurationStorage.getClass(),
-                changedEntries
-            ));
+        storagesRootsMap.put(configurationStorage.getClass(), new StorageRoots(storageRootsMap, data.version()));
 
-            // TODO: IGNITE-14118 iterate over data and fill Configurators
-        }
+        configurationStorage.addListener(changedEntries -> updateFromListener(
+            configurationStorage.getClass(),
+            changedEntries
+        ));
     }
 
     /**
@@ -266,7 +270,8 @@ public class ConfigurationChanger {
      * @param changes Configuration changes.
      * @return Validation results.
      */
-    @SuppressWarnings("unused") // Will be used in the future, I promise (IGNITE-14183).
+    // Will be used in the future, I promise (IGNITE-14183).
+    @SuppressWarnings("unused")
     private ValidationResult validate(
         StorageRoots storageRoots,
         Map<RootKey<?>, TraversableTreeNode> changes
@@ -279,8 +284,11 @@ public class ConfigurationChanger {
 
             final Configurator<?> configurator = configurators.get(rootKey);
 
-            List<ValidationIssue> list = configurator.validateChanges(changesForRoot);
-            issues.addAll(list);
+            // TODO IGNITE-14183 This will be fixed later
+            if (configurator != null) {
+                List<ValidationIssue> list = configurator.validateChanges(changesForRoot);
+                issues.addAll(list);
+            }
         }
 
         return new ValidationResult(issues);
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationProperty.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationProperty.java
index 4947b7e..e61b720 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationProperty.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationProperty.java
@@ -17,8 +17,6 @@
 
 package org.apache.ignite.configuration;
 
-import org.apache.ignite.configuration.validation.ConfigurationValidationException;
-
 /**
  * Base interface for configuration.
  * @param <VALUE> Type of the value.
@@ -36,11 +34,4 @@ public interface ConfigurationProperty<VALUE, CHANGE> {
      * @return Value of this property.
      */
     VALUE value();
-
-    /**
-     * Change this configuration node value.
-     * @param change CHANGE object.
-     * @throws ConfigurationValidationException If validation failed.
-     */
-    void change(CHANGE change) throws ConfigurationValidationException;
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationRegistry.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationRegistry.java
index 7597805..5c0c7c5 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationRegistry.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationRegistry.java
@@ -17,35 +17,41 @@
 
 package org.apache.ignite.configuration;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.function.BiFunction;
 import java.util.function.Supplier;
 import org.apache.ignite.configuration.annotation.ConfigurationRoot;
 import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.RootKeyImpl;
 import org.apache.ignite.configuration.storage.ConfigurationStorage;
 import org.apache.ignite.configuration.tree.InnerNode;
 
 /** */
 public class ConfigurationRegistry {
     /** */
-    private final Map<String, Configurator<?>> configs = new HashMap<>();
+    private final Map<String, DynamicConfiguration<?, ?, ?>> configs = new HashMap<>();
 
     /** */
-    public <T extends DynamicConfiguration<?, ?, ?>> void registerConfigurator(Configurator<T> unitConfig) {
-        String key = unitConfig.getRoot().key();
+    private final ConfigurationChanger changer = new ConfigurationChanger();
 
-        configs.put(key, unitConfig);
+    /** */
+    public void registerRootKey(RootKey<?> rootKey) {
+        changer.addRootKey(rootKey);
+
+        configs.put(rootKey.key(), (DynamicConfiguration<?, ?, ?>)rootKey.createPublicRoot(changer));
+
+        //TODO IGNITE-14180 link these two entities.
     }
 
     /** */
-    public <V, C, T extends ConfigurationTree<V, C>> T getConfiguration(RootKey<T> rootKey) {
-        return (T) configs.get(rootKey.key()).getRoot();
+    public void registerStorage(ConfigurationStorage configurationStorage) {
+        changer.init(configurationStorage);
     }
 
     /** */
-    public Map<String, Configurator<? extends DynamicConfiguration<?, ?, ?>>> getConfigurators() {
-        return Collections.unmodifiableMap(configs);
+    public <V, C, T extends ConfigurationTree<V, C>> T getConfiguration(RootKey<T> rootKey) {
+        return (T)configs.get(rootKey.key());
     }
 
     /**
@@ -53,14 +59,16 @@ public class ConfigurationRegistry {
      * Does not register this root anywhere, used for static object initialization only.
      *
      * @param rootName Name of the root as described in {@link ConfigurationRoot#rootName()}.
-     * @param storageType Storage class as descried in {@link ConfigurationRoot#storage()}.
+     * @param storageType Storage class as described in {@link ConfigurationRoot#storage()}.
      * @param rootSupplier Closure to instantiate internal configuration tree roots.
+     * @param publicRootCreator Function to create public user-facing tree instance.
      */
     public static <T extends ConfigurationTree<?, ?>> RootKey<T> newRootKey(
         String rootName,
         Class<? extends ConfigurationStorage> storageType,
-        Supplier<InnerNode> rootSupplier
+        Supplier<InnerNode> rootSupplier,
+        BiFunction<RootKey<T>, ConfigurationChanger, T> publicRootCreator
     ) {
-        return new RootKeyImpl<>(rootName, storageType, rootSupplier);
+        return new RootKeyImpl<>(rootName, storageType, rootSupplier, publicRootCreator);
     }
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationTree.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationTree.java
index 2df36b7..28e84de 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationTree.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationTree.java
@@ -18,6 +18,9 @@
 package org.apache.ignite.configuration;
 
 import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+import org.apache.ignite.configuration.validation.ConfigurationValidationException;
 
 /**
  * Configuration tree with configuration values and other configuration trees as child nodes.
@@ -27,4 +30,11 @@ import java.util.Map;
 public interface ConfigurationTree<VALUE, CHANGE> extends ConfigurationProperty<VALUE, CHANGE> {
     /** Children of the tree. */
     Map<String, ConfigurationProperty<?, ?>> members();
+
+    /**
+     * Change this configuration node value.
+     * @param change CHANGE object.
+     * @throws ConfigurationValidationException If validation failed.
+     */
+    Future<Void> change(Consumer<CHANGE> change) throws ConfigurationValidationException;
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationValue.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationValue.java
index 5e6229c..4739521 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationValue.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationValue.java
@@ -17,9 +17,21 @@
 
 package org.apache.ignite.configuration;
 
+import java.util.concurrent.Future;
+import org.apache.ignite.configuration.validation.ConfigurationValidationException;
+
 /**
  * Configuration value.
  * @param <VALUE> Type of the value.
  */
 public interface ConfigurationValue<VALUE> extends ConfigurationProperty<VALUE, VALUE> {
+
+    /**
+     * Update this configuration node value.
+     *
+     * @param change New value for the configuration. Must not be null.
+     * @returns Future that signifies end of the update operation. Can also be completed with
+     *      {@link ConfigurationValidationException} and {@link ConfigurationChangeException}.
+     */
+    Future<Void> update(VALUE change) throws ConfigurationValidationException;
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/Configurator.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/Configurator.java
index d3f42c9..a3af965 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/Configurator.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/Configurator.java
@@ -18,8 +18,6 @@
 package org.apache.ignite.configuration;
 
 import java.io.Serializable;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -27,11 +25,8 @@ import java.util.Map;
 import java.util.function.Function;
 import org.apache.ignite.configuration.internal.DynamicConfiguration;
 import org.apache.ignite.configuration.internal.DynamicProperty;
-import org.apache.ignite.configuration.internal.Modifier;
-import org.apache.ignite.configuration.internal.selector.Selector;
 import org.apache.ignite.configuration.internal.validation.MemberKey;
 import org.apache.ignite.configuration.tree.TraversableTreeNode;
-import org.apache.ignite.configuration.validation.ConfigurationValidationException;
 import org.apache.ignite.configuration.validation.FieldValidator;
 import org.apache.ignite.configuration.validation.ValidationIssue;
 
@@ -59,24 +54,7 @@ public class Configurator<T extends DynamicConfiguration<?, ?, ?>> {
     public static <VIEW, INIT, CHANGE, CONF extends DynamicConfiguration<VIEW, INIT, CHANGE>> Configurator<CONF> create(
         Function<Configurator<CONF>, CONF> rootBuilder
     ) {
-        return new Configurator<>(rootBuilder, null);
-    }
-
-    /**
-     *
-     * @param rootBuilder
-     * @param init
-     * @param <VIEW>
-     * @param <INIT>
-     * @param <CHANGE>
-     * @param <CONF>
-     * @return
-     */
-    public static <VIEW, INIT, CHANGE, CONF extends DynamicConfiguration<VIEW, INIT, CHANGE>> Configurator<CONF> create(
-        Function<Configurator<CONF>, CONF> rootBuilder,
-        INIT init
-    ) {
-        return new Configurator<>(rootBuilder, init);
+        return new Configurator<>(rootBuilder);
     }
 
     /**
@@ -84,87 +62,15 @@ public class Configurator<T extends DynamicConfiguration<?, ?, ?>> {
      * @param rootBuilder Function, that creates configuration root.
      */
     private <VIEW, INIT, CHANGE, CONF extends DynamicConfiguration<VIEW, INIT, CHANGE>> Configurator(
-        Function<Configurator<CONF>, CONF> rootBuilder,
-        INIT init
+        Function<Configurator<CONF>, CONF> rootBuilder
     ) {
         final CONF built = rootBuilder.apply((Configurator<CONF>) this);
 
-        if (init != null)
-            built.init(init);
-
         root = (T) built;
     }
 
     /**
      *
-     * @param selector
-     * @param <TARGET>
-     * @param <VIEW>
-     * @param <INIT>
-     * @param <CHANGE>
-     * @return
-     */
-    public <TARGET extends Modifier<VIEW, INIT, CHANGE>, VIEW, INIT, CHANGE> VIEW getPublic(
-        Selector<T, TARGET, VIEW, INIT, CHANGE> selector
-    ) {
-        return selector.select(root).value();
-    }
-
-    /**
-     *
-     */
-    public Class<?> getChangeType() {
-        Type sClass = root.getClass().getGenericSuperclass();
-
-        assert sClass instanceof ParameterizedType;
-
-        ParameterizedType pt = (ParameterizedType)sClass;
-
-        assert pt.getActualTypeArguments().length == 3;
-
-        return (Class<?>) pt.getActualTypeArguments()[2];
-    }
-
-    /**
-     *
-     * @param selector
-     * @param newValue
-     * @param <TARGET>
-     * @param <VIEW>
-     * @param <INIT>
-     * @param <CHANGE>
-     * @throws ConfigurationValidationException
-     */
-    public <TARGET extends Modifier<VIEW, INIT, CHANGE>, VIEW, INIT, CHANGE> void set(
-        Selector<T, TARGET, VIEW, INIT, CHANGE> selector,
-        CHANGE newValue
-    ) throws ConfigurationValidationException {
-        final T copy = (T) root.copy();
-
-        final TARGET select = selector.select(copy);
-        select.changeWithoutValidation(newValue);
-        copy.validate(root);
-
-        selector.select(root).changeWithoutValidation(newValue);
-    }
-
-    /**
-     *
-     * @param selector
-     * @param <TARGET>
-     * @param <VIEW>
-     * @param <INIT>
-     * @param <CHANGE>
-     * @return
-     */
-    public <TARGET extends Modifier<VIEW, INIT, CHANGE>, VIEW, INIT, CHANGE> ConfigurationProperty<VIEW, CHANGE> getInternal(
-        Selector<T, TARGET, VIEW, INIT, CHANGE> selector
-    ) {
-        return selector.select(root);
-    }
-
-    /**
-     *
      * @param aClass
      * @param key
      * @param validators
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/RootKey.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/RootKey.java
index d253b05..e49db7b 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/RootKey.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/RootKey.java
@@ -26,8 +26,11 @@ public abstract class RootKey<T extends ConfigurationTree<?, ?>> {
     public abstract String key();
 
     /** */
-    abstract Class<? extends ConfigurationStorage> getStorageType();
+    protected abstract Class<? extends ConfigurationStorage> getStorageType();
 
     /** */
-    abstract InnerNode createRootNode();
+    protected abstract InnerNode createRootNode();
+
+    /** */
+    protected abstract T createPublicRoot(ConfigurationChanger changer);
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/ConfigurationNode.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/ConfigurationNode.java
new file mode 100644
index 0000000..62bbba5
--- /dev/null
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/ConfigurationNode.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.configuration.internal;
+
+import java.util.List;
+import java.util.NoSuchElementException;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.internal.util.ConfigurationUtil;
+import org.apache.ignite.configuration.internal.util.KeyNotFoundException;
+import org.apache.ignite.configuration.tree.TraversableTreeNode;
+
+/**
+ * Super class for dynamic configuration tree nodes. Has all common data and value retrieving algorithm in it.
+ */
+public abstract class ConfigurationNode<VIEW> {
+    /** Full path to the current node. */
+    protected final List<String> keys;
+
+    /** Name of the current node. Same as last element of {@link #keys}. */
+    protected final String key;
+
+    /** Root key instance for the current trees root. */
+    protected final RootKey<?> rootKey;
+
+    /** Configuration changer instance to get latest value of the root. */
+    protected final ConfigurationChanger changer;
+
+    /**
+     * Cached value of current trees root. Useful to determine whether you have the latest configuration value or not.
+     */
+    private volatile TraversableTreeNode cachedRootNode;
+
+    /** Cached configuration value. Immutable. */
+    private VIEW val;
+
+    /**
+     * Validity flag. Configuration is declared invalid if it's a part of named list configuration and corresponding
+     * entry is already removed.
+     */
+    private boolean invalid;
+
+    /**
+     * Constructor.
+     *
+     * @param prefix Configuration prefix.
+     * @param key Configuration key.
+     * @param rootKey Root key.
+     * @param changer Configuration changer.
+     */
+    protected ConfigurationNode(List<String> prefix, String key, RootKey<?> rootKey, ConfigurationChanger changer) {
+        this.keys = ConfigurationUtil.appendKey(prefix, key);
+        this.key = key;
+        this.rootKey = rootKey;
+        this.changer = changer;
+    }
+
+    /**
+     * Returns latest value of the configuration or throws exception.
+     *
+     * @return Latest configuration value.
+     * @throws NoSuchElementException If configuration is a part of already deleted named list configuration entry.
+     */
+    protected final VIEW refreshValue() throws NoSuchElementException {
+        if (invalid)
+            throw noSuchElementException();
+
+        TraversableTreeNode newRootNode = changer.getRootNode(rootKey);
+        TraversableTreeNode oldRootNode = cachedRootNode;
+
+        if (oldRootNode == newRootNode)
+            return val;
+
+        try {
+            VIEW newVal = (VIEW)ConfigurationUtil.find(keys.subList(1, keys.size()), newRootNode);
+
+            synchronized (this) {
+                if (cachedRootNode == oldRootNode) {
+                    cachedRootNode = newRootNode;
+
+                    refreshValue0(newVal);
+
+                    return val = newVal;
+                }
+                else {
+                    if (invalid)
+                        throw noSuchElementException();
+
+                    return val;
+                }
+            }
+        }
+        catch (KeyNotFoundException e) {
+            synchronized (this) {
+                invalid = true;
+
+                cachedRootNode = newRootNode;
+            }
+
+            throw noSuchElementException();
+        }
+    }
+
+    /**
+     * @return Exception instance with a proper error message.
+     */
+    private NoSuchElementException noSuchElementException() {
+        return new NoSuchElementException(ConfigurationUtil.join(keys));
+    }
+
+    /**
+     * Callback from {@link #refreshValue()} that's called right before the update. Synchronized.
+     *
+     * @param newValue New configuration value.
+     */
+    protected abstract void refreshValue0(VIEW newValue);
+}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java
index a739f7c..5b2bbeb 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java
@@ -21,77 +21,51 @@ import java.io.Serializable;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
 import java.util.stream.Collectors;
+import org.apache.ignite.configuration.ConfigurationChanger;
 import org.apache.ignite.configuration.ConfigurationProperty;
 import org.apache.ignite.configuration.ConfigurationTree;
-import org.apache.ignite.configuration.Configurator;
-import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.tree.ConfigurationSource;
+import org.apache.ignite.configuration.tree.ConstructableTreeNode;
+import org.apache.ignite.configuration.tree.InnerNode;
 import org.apache.ignite.configuration.validation.ConfigurationValidationException;
 import org.apache.ignite.configuration.validation.FieldValidator;
 
 /**
  * This class represents configuration root or node.
  */
-public abstract class DynamicConfiguration<VIEW, INIT, CHANGE> implements Modifier<VIEW, INIT, CHANGE>, ConfigurationTree<VIEW, CHANGE> {
-    /** Fully qualified name of the configuration. */
-    protected final String qualifiedName;
-
-    /** Configuration key. */
-    protected final String key;
-
-    /** Configuration prefix. */
-    protected final String prefix;
+public abstract class DynamicConfiguration<VIEW, INIT, CHANGE> extends ConfigurationNode<VIEW> implements ConfigurationProperty<VIEW, CHANGE>, ConfigurationTree<VIEW, CHANGE> {
 
     /** Configuration members (leaves and nodes). */
-    protected final Map<String, Modifier<?, ?, ?>> members = new HashMap<>();
-
-    /** Root configuration node. */
-    protected final DynamicConfiguration<?, ?, ?> root;
-
-    /** {@code true} if this is a member of {@link NamedListConfiguration}. */
-    protected final boolean isNamed;
-
-    /** Configurator that this configuration is attached to. */
-    protected final Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator;
+    protected final Map<String, ConfigurationProperty<?, ?>> members = new HashMap<>();
 
     /**
      * Constructor.
      * @param prefix Configuration prefix.
      * @param key Configuration key.
-     * @param isNamed Is this a part of named configuration.
-     * @param configurator Configurator that this object is attached to.
-     * @param root Root configuration.
+     * @param rootKey Root key.
+     * @param changer Configuration changer.
      */
     protected DynamicConfiguration(
-        String prefix,
+        List<String> prefix,
         String key,
-        boolean isNamed,
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
-        DynamicConfiguration<?, ?, ?> root
+        RootKey<?> rootKey,
+        ConfigurationChanger changer
     ) {
-        this.prefix = prefix;
-        this.isNamed = isNamed;
-        this.configurator = configurator;
-
-        this.key = key;
-        if (root == null)
-            this.qualifiedName = key;
-        else {
-            if (isNamed)
-                qualifiedName = String.format("%s[%s]", prefix, key);
-            else
-                qualifiedName = String.format("%s.%s", prefix, key);
-        }
-
-        this.root = root != null ? root : this;
+        super(prefix, key, rootKey, changer);
     }
 
     /**
      * Add new configuration member.
      * @param member Configuration member (leaf or node).
-     * @param <M> Type of member.
+     * @param <P> Type of member.
      */
-    protected <M extends Modifier<?, ?, ?>> void add(M member) {
+    protected <P extends ConfigurationProperty<?, ?>> void add(P member) {
         members.put(member.key(), member);
     }
 
@@ -108,43 +82,55 @@ public abstract class DynamicConfiguration<VIEW, INIT, CHANGE> implements Modifi
     ) {
         members.put(member.key(), member);
 
-        configurator.addValidations((Class<? extends ConfigurationTree<?, ?>>) getClass(), member.key(), validators);
+        //TODO IGNITE-14183
+//        configurator.addValidations((Class<? extends ConfigurationTree<?, ?>>) getClass(), member.key(), validators);
     }
 
     /** {@inheritDoc} */
-    @Override public void change(CHANGE change) throws ConfigurationValidationException {
-        configurator.set(BaseSelectors.find(qualifiedName), change);
+    @Override public Future<Void> change(Consumer<CHANGE> change) throws ConfigurationValidationException {
+        Objects.requireNonNull(change, "Configuration consumer cannot be null.");
+
+        InnerNode rootNodeChange = ((RootKeyImpl)rootKey).createRootNode();
+
+        if (keys.size() == 1) {
+            // Current node is a root.
+            change.accept((CHANGE)rootNodeChange);
+        }
+        else {
+            assert keys instanceof RandomAccess;
+
+            rootNodeChange.construct(keys.get(1), new ConfigurationSource() {
+                private int i = 1;
+
+                @Override public void descend(ConstructableTreeNode node) {
+                    if (++i == keys.size())
+                        change.accept((CHANGE)node);
+                    else
+                        node.construct(keys.get(i), this);
+                }
+            });
+        }
+
+        return changer.change(Map.of(rootKey, rootNodeChange));
     }
 
     /** {@inheritDoc} */
-    @Override public String key() {
+    @Override public final String key() {
         return key;
     }
 
-    /**
-     * Create a deep copy of this DynamicConfiguration, but attaching it to another configuration root.
-     * @param root New configuration root.
-     * @return Copy of this configuration.
-     */
-    public abstract DynamicConfiguration<VIEW, INIT, CHANGE> copy(DynamicConfiguration<?, ?, ?> root);
-
-    /**
-     * Create a deep copy of this DynamicConfiguration, making it root configuration (so this method must be called
-     * only on root configuration object).
-     * @return Copy of this configuration.
-     */
-    public final DynamicConfiguration<VIEW, INIT, CHANGE> copy() {
-        return copy(null);
-    }
-
     /** {@inheritDoc} */
-    @Override public void validate(DynamicConfiguration<?, ?, ?> oldRoot) throws ConfigurationValidationException {
-        for (Modifier<?, ?, ?> member : members.values())
-            member.validate(oldRoot);
+    @Override public final VIEW value() {
+        return refreshValue();
     }
 
     /** {@inheritDoc} */
     @Override public Map<String, ConfigurationProperty<?, ?>> members() {
         return members.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
     }
+
+    /** {@inheritDoc} */
+    @Override protected void refreshValue0(VIEW newValue) {
+        // No-op.
+    }
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicProperty.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicProperty.java
index 591a294..883ad93 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicProperty.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicProperty.java
@@ -20,116 +20,41 @@ package org.apache.ignite.configuration.internal;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.RandomAccess;
+import java.util.concurrent.Future;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.ConfigurationProperty;
 import org.apache.ignite.configuration.ConfigurationValue;
-import org.apache.ignite.configuration.Configurator;
 import org.apache.ignite.configuration.PropertyListener;
-import org.apache.ignite.configuration.internal.selector.BaseSelectors;
-import org.apache.ignite.configuration.internal.validation.MemberKey;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.tree.ConfigurationSource;
+import org.apache.ignite.configuration.tree.ConstructableTreeNode;
+import org.apache.ignite.configuration.tree.InnerNode;
 import org.apache.ignite.configuration.validation.ConfigurationValidationException;
-import org.apache.ignite.configuration.validation.FieldValidator;
 
 /**
  * Holder for property value. Expected to be used with numbers, strings and other immutable objects, e.g. IP addresses.
  */
-public class DynamicProperty<T extends Serializable> implements Modifier<T, T, T>, ConfigurationValue<T> {
-    /** Name of property. */
-    private final String name;
-
-    /** Member key. */
-    private final MemberKey memberKey;
-
-    /** Full name with prefix. */
-    private final String qualifiedName;
-
-    /** Property value. */
-    protected volatile T val;
-
+public class DynamicProperty<T extends Serializable> extends ConfigurationNode<T> implements ConfigurationProperty<T, T>, ConfigurationValue<T> {
     /** Listeners of property update. */
     private final List<PropertyListener<T, T>> updateListeners = new ArrayList<>();
 
-    /** Configurator that this configuration is attached to. */
-    protected final Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator;
-
-    /** Configuration root. */
-    protected final DynamicConfiguration<?, ?, ?> root;
-
     /**
      * Constructor.
      * @param prefix Property prefix.
-     * @param name Property name.
-     * @param memberKey Property member key.
-     * @param configurator Configurator to attach to.
-     * @param root Configuration root.
+     * @param key Property name.
+     * @param rootKey Root key.
+     * @param changer Configuration changer.
      */
     public DynamicProperty(
-        String prefix,
-        String name,
-        MemberKey memberKey,
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
-        DynamicConfiguration<?, ?, ?> root
+        List<String> prefix,
+        String key,
+        RootKey<?> rootKey,
+        ConfigurationChanger changer
     ) {
-        this(prefix, name, memberKey, null, configurator, root);
-    }
-
-    /**
-     * Constructor.
-     * @param prefix Property prefix.
-     * @param name Property name.
-     * @param memberKey Property member key.
-     * @param defaultValue Default value for the property.
-     * @param configurator Configurator to attach to.
-     * @param root Configuration root.
-     */
-    public DynamicProperty(
-        String prefix,
-        String name,
-        MemberKey memberKey,
-        T defaultValue,
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
-        DynamicConfiguration<?, ?, ?> root
-    ) {
-        this(defaultValue, name, memberKey, String.format("%s.%s", prefix, name), configurator, root, false);
-    }
-
-    /**
-     * Copy constructor.
-     * @param base Property to copy from.
-     * @param root Configuration root.
-     */
-    private DynamicProperty(
-        DynamicProperty<T> base,
-        DynamicConfiguration<?, ?, ?> root
-    ) {
-        this(base.val, base.name, base.memberKey, base.qualifiedName, base.configurator, root, true);
-    }
-
-    /**
-     * Constructor.
-     * @param value Property value.
-     * @param name Property name.
-     * @param memberKey Member key.
-     * @param qualifiedName Fully qualified name of the property.
-     * @param configurator Configurator.
-     * @param root Configuration root.
-     */
-    private DynamicProperty(
-        T value,
-        String name,
-        MemberKey memberKey,
-        String qualifiedName,
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
-        DynamicConfiguration<?, ?, ?> root,
-        boolean isCopy
-    ) {
-        this.name = name;
-        this.memberKey = memberKey;
-        this.qualifiedName = qualifiedName;
-        this.val = value;
-        this.configurator = configurator;
-        this.root = root;
-
-        if (isCopy)
-            configurator.onAttached(this);
+        super(prefix, key, rootKey, changer);
     }
 
     /**
@@ -142,61 +67,46 @@ public class DynamicProperty<T extends Serializable> implements Modifier<T, T, T
 
     /** {@inheritDoc} */
     @Override public T value() {
-        return val;
+        return refreshValue();
     }
 
     /** {@inheritDoc} */
-    @Override public void change(T object) throws ConfigurationValidationException {
-        configurator.set(BaseSelectors.find(qualifiedName), object);
-    }
+    @Override public Future<Void> update(T newValue) throws ConfigurationValidationException {
+        Objects.requireNonNull(newValue, "Configuration value cannot be null.");
 
-    /** {@inheritDoc} */
-    @Override public void init(T object) throws ConfigurationValidationException {
-        this.val = object;
-    }
+        InnerNode rootNodeChange = ((RootKeyImpl)rootKey).createRootNode();
 
-    /** {@inheritDoc} */
-    @Override public void changeWithoutValidation(T object) {
-        this.val = object;
+        assert keys instanceof RandomAccess;
+        assert !keys.isEmpty();
 
-        for (PropertyListener<T, T> listener : updateListeners)
-            listener.update(object, this);
-    }
+        rootNodeChange.construct(keys.get(1), new ConfigurationSource() {
+            private int i = 1;
 
-    /** {@inheritDoc} */
-    @Override public void validate(DynamicConfiguration<?, ?, ?> oldRoot) throws ConfigurationValidationException {
-        final List<? extends FieldValidator<? extends Serializable, ? extends DynamicConfiguration<?, ?, ?>>> validators = configurator.validators(memberKey);
+            @Override public void descend(ConstructableTreeNode node) {
+                assert i < keys.size() - 1;
 
-        for (FieldValidator<? extends Serializable, ? extends DynamicConfiguration<?, ?, ?>> validator : validators)
-            ((FieldValidator<T, DynamicConfiguration<?, ?, ?>>) validator).validate(val, root, oldRoot);
-    }
+                node.construct(keys.get(++i), this);
+            }
 
-    /** {@inheritDoc} */
-    @Override public String key() {
-        return name;
-    }
+            @Override public <T> T unwrap(Class<T> clazz) {
+                assert i == keys.size() - 1;
 
-    /**
-     * Get fully qualified name of this property.
-     * @return Fully qualified name.
-     */
-    public String qualifiedName() {
-        return qualifiedName;
-    }
+                assert clazz.isInstance(newValue);
 
-    public void setSilently(T serializable) {
-        val = serializable;
+                return clazz.cast(newValue);
+            }
+        });
 
-        for (PropertyListener<T, T> listener : updateListeners)
-            listener.update(val, this);
+        return changer.change(Map.of(rootKey, rootNodeChange));
     }
 
-    /**
-     * Create a deep copy of this DynamicProperty, but attaching it to another configuration root.
-     * @param newRoot New configuration root.
-     * @return Copy of this property.
-     */
-    public DynamicProperty<T> copy(DynamicConfiguration<?, ?, ?> newRoot) {
-        return new DynamicProperty<>(this, newRoot);
+    /** {@inheritDoc} */
+    @Override public String key() {
+        return key;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void refreshValue0(T newValue) {
+        // No-op.
     }
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/Modifier.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/Modifier.java
deleted file mode 100644
index fcc2ce0..0000000
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/Modifier.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.internal;
-
-import org.apache.ignite.configuration.ConfigurationProperty;
-import org.apache.ignite.configuration.validation.ConfigurationValidationException;
-
-/**
- * Interface for configuration nodes and leaves.
- */
-public interface Modifier<VIEW, INIT, CHANGE> extends ConfigurationProperty<VIEW, CHANGE> {
-    /**
-     * Change this configuration node value, but without validation.
-     * @param change CHANGE object.
-     */
-    void changeWithoutValidation(CHANGE change);
-
-    /**
-     * Initialize this configuration node with value.
-     * @param init INIT object.
-     * @throws ConfigurationValidationException If validation failed.
-     */
-    void init(INIT init) throws ConfigurationValidationException;
-
-    /**
-     * Validate this configuration node against old configuration root thus comparing new configuration "snapshot"
-     * with a previous one.
-     * @param oldRoot Old configuration root.
-     * @throws ConfigurationValidationException If validation failed.
-     */
-    void validate(DynamicConfiguration<?, ?, ?> oldRoot) throws ConfigurationValidationException;
-}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/NamedListConfiguration.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/NamedListConfiguration.java
index 98e2619..5f3f450 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/NamedListConfiguration.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/NamedListConfiguration.java
@@ -18,109 +18,71 @@
 package org.apache.ignite.configuration.internal;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.function.BiFunction;
-import java.util.stream.Collectors;
-import org.apache.ignite.configuration.Configurator;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.tree.NamedListChange;
+import org.apache.ignite.configuration.tree.NamedListInit;
+import org.apache.ignite.configuration.tree.NamedListView;
 
 /**
  * Named configuration wrapper.
  */
-public class NamedListConfiguration<VIEW, T extends Modifier<VIEW, INIT, CHANGE>, INIT, CHANGE>
-    extends DynamicConfiguration<NamedList<VIEW>, NamedList<INIT>, NamedList<CHANGE>> {
+public class NamedListConfiguration<VIEW, T extends ConfigurationProperty<VIEW, CHANGE>, INIT, CHANGE>
+    extends DynamicConfiguration<NamedListView<VIEW>, NamedListInit<INIT>, NamedListChange<CHANGE, INIT>> {
     /** Creator of named configuration. */
-    private final BiFunction<String, String, T> creator;
+    private final BiFunction<List<String>, String, T> creator;
 
     /** Named configurations. */
-    private final Map<String, T> values = new HashMap<>();
+    private volatile Map<String, T> values = new HashMap<>();
 
     /**
      * Constructor.
      * @param prefix Configuration prefix.
      * @param key Configuration key.
-     * @param configurator Configurator that this object is attached to.
-     * @param root Root configuration.
+     * @param rootKey Root key.
+     * @param changer Configuration changer.
      * @param creator Underlying configuration creator function.
      */
     public NamedListConfiguration(
-        String prefix,
+        List<String> prefix,
         String key,
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
-        DynamicConfiguration<?, ?, ?> root,
-        BiFunction<String, String, T> creator
-    ) {
-        super(prefix, key, false, configurator, root);
+        RootKey<?> rootKey,
+        ConfigurationChanger changer,
+        BiFunction<List<String>, String, T> creator) {
+        super(prefix, key, rootKey, changer);
         this.creator = creator;
     }
 
     /**
-     * Copy constructor.
-     * @param base Base to copy from.
-     * @param configurator Configurator to attach to.
-     * @param root Root of the configuration.
-     */
-    private NamedListConfiguration(
-        NamedListConfiguration<VIEW, T, INIT, CHANGE> base,
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
-        DynamicConfiguration<?, ?, ?> root
-    ) {
-        super(base.prefix, base.key, false, configurator, root);
-
-        this.creator = base.creator;
-
-        for (Map.Entry<String, T> entry : base.values.entrySet()) {
-            String k = entry.getKey();
-            T value = entry.getValue();
-
-            final T copy = (T) ((DynamicConfiguration<VIEW, INIT, CHANGE>) value).copy(root);
-            add(copy);
-
-            this.values.put(k, copy);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override public void init(NamedList<INIT> list) {
-        list.getValues().forEach((key, init) -> {
-            if (!values.containsKey(key)) {
-                final T created = creator.apply(qualifiedName, key);
-                add(created);
-                values.put(key, created);
-            }
-
-            values.get(key).init(init);
-        });
-    }
-
-    /**
      * Get named configuration by name.
      * @param name Name.
      * @return Configuration.
      */
     public T get(String name) {
+        refreshValue();
+
+        //TODO IGNITE-14182 Exceptions.
         return values.get(name);
     }
 
     /** {@inheritDoc} */
-    @Override public NamedList<VIEW> value() {
-        return new NamedList<>(values.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, it -> it.getValue().value())));
-    }
+    @Override protected synchronized void refreshValue0(NamedListView<VIEW> newValue) {
+        Map<String, T> oldValues = this.values;
+        Map<String, T> newValues = new HashMap<>();
 
-    /** {@inheritDoc} */
-    @Override public void changeWithoutValidation(NamedList<CHANGE> list) {
-        list.getValues().forEach((key, change) -> {
-            if (!values.containsKey(key)) {
-                final T created = creator.apply(qualifiedName, key);
-                add(created);
-                values.put(key, created);
-            }
+        for (String key : newValue.namedListKeys()) {
+            T oldElement = oldValues.get(key);
 
-            values.get(key).changeWithoutValidation(change);
-        });
-    }
+            if (oldElement != null)
+                newValues.put(key, oldElement);
+            else
+                newValues.put(key, creator.apply(keys, key));
+        }
 
-    /** {@inheritDoc} */
-    @Override public NamedListConfiguration<VIEW, T, INIT, CHANGE> copy(DynamicConfiguration<?, ?, ?> root) {
-        return new NamedListConfiguration<>(this, configurator, root);
+        this.values = newValues;
     }
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/RootKeyImpl.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/RootKeyImpl.java
similarity index 60%
rename from modules/configuration/src/main/java/org/apache/ignite/configuration/RootKeyImpl.java
rename to modules/configuration/src/main/java/org/apache/ignite/configuration/internal/RootKeyImpl.java
index 61537c7..66c04ea 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/RootKeyImpl.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/RootKeyImpl.java
@@ -15,14 +15,18 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.configuration;
+package org.apache.ignite.configuration.internal;
 
+import java.util.function.BiFunction;
 import java.util.function.Supplier;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.ConfigurationTree;
+import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.storage.ConfigurationStorage;
 import org.apache.ignite.configuration.tree.InnerNode;
 
 /** */
-class RootKeyImpl<T extends ConfigurationTree<?, ?>> extends RootKey<T> {
+public class RootKeyImpl<T extends ConfigurationTree<?, ?>> extends RootKey<T> {
     /** */
     private final String rootName;
 
@@ -33,10 +37,19 @@ class RootKeyImpl<T extends ConfigurationTree<?, ?>> extends RootKey<T> {
     private final Supplier<InnerNode> rootSupplier;
 
     /** */
-    RootKeyImpl(String rootName, Class<? extends ConfigurationStorage> storageType, Supplier<InnerNode> rootSupplier) {
+    private final BiFunction<RootKey<T>, ConfigurationChanger, T> publicRootCreator;
+
+    /** */
+    public RootKeyImpl(
+        String rootName,
+        Class<? extends ConfigurationStorage> storageType,
+        Supplier<InnerNode> rootSupplier,
+        BiFunction<RootKey<T>, ConfigurationChanger, T> publicRootCreator
+    ) {
         this.rootName = rootName;
         this.storageType = storageType;
         this.rootSupplier = rootSupplier;
+        this.publicRootCreator = publicRootCreator;
     }
 
     /** {@inheritDoc} */
@@ -45,12 +58,17 @@ class RootKeyImpl<T extends ConfigurationTree<?, ?>> extends RootKey<T> {
     }
 
     /** {@inheritDoc} */
-    @Override Class<? extends ConfigurationStorage> getStorageType() {
+    @Override protected Class<? extends ConfigurationStorage> getStorageType() {
         return storageType;
     }
 
     /** {@inheritDoc} */
-    @Override InnerNode createRootNode() {
+    @Override protected InnerNode createRootNode() {
         return rootSupplier.get();
     }
+
+    /** {@inheritDoc} */
+    @Override protected T createPublicRoot(ConfigurationChanger changer) {
+        return publicRootCreator.apply(this, changer);
+    }
 }
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java
deleted file mode 100644
index deeb83a..0000000
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.internal.selector;
-
-import java.lang.invoke.MethodHandle;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import org.apache.ignite.configuration.internal.DynamicConfiguration;
-import org.apache.ignite.configuration.internal.Modifier;
-
-/**
- * Base selector holder.
- */
-public class BaseSelectors {
-    /** Map from string representation of selector to {@link SelectorHolder}. */
-    private static final Map<String, SelectorHolder> selectors = new HashMap<>();
-
-    /**
-     * Get selector from selectors map by key.
-     *
-     * Valid formats for selector key:
-     * <ul>
-     *     <li>root.inner.option.field in case of static config field</li>
-     *     <li>root.inner.named[name].field in case of dynamic (named) config field</li>
-     * </ul>
-     *
-     * @param name Selector name.
-     * @return Selector.
-     */
-    public static <ROOT extends DynamicConfiguration<?, ?, ?>, TARGET extends Modifier<VIEW, INIT, CHANGE>, VIEW, INIT, CHANGE> Selector<ROOT, TARGET, VIEW, INIT, CHANGE> find(String name) {
-        String[] nameParts = name.split("\\.");
-
-        List<String> arguments = new ArrayList<>();
-        StringBuilder keyBuilder = new StringBuilder();
-
-        for (int i = 0; i < nameParts.length; i++) {
-            String part = nameParts[i];
-
-            int start = part.indexOf('[');
-
-            String methodArg = null;
-
-            if (start != -1) {
-                int end = part.indexOf(']');
-
-                if (end != -1) {
-                    methodArg = part.substring(start + 1, end);
-                    part = part.substring(0, start);
-                }
-            }
-
-            if (methodArg != null)
-                arguments.add(methodArg);
-
-            keyBuilder.append(part);
-
-            if (i != nameParts.length - 1)
-                keyBuilder.append('.');
-        }
-
-        final String key = keyBuilder.toString();
-
-        final SelectorHolder selector = selectors.get(key);
-
-        if (selector == null) {
-            final int lastDot = key.lastIndexOf('.');
-
-            if (lastDot != -1) {
-                String partialKey = key.substring(0, lastDot);
-
-                final SelectorHolder partialSelector = selectors.get(partialKey);
-
-                if (partialSelector != null) {
-                    final String availableOptions = selectors.keySet().stream().filter(s -> s.startsWith(partialKey)).collect(Collectors.joining(", "));
-                    throw new SelectorNotFoundException("Selector " + key + " was not found, available options are: " + availableOptions);
-                }
-            }
-        }
-
-        try {
-            return (Selector<ROOT, TARGET, VIEW, INIT, CHANGE>) selector.get(arguments);
-        } catch (Throwable throwable) {
-            throw new SelectorNotFoundException("Failed to get selector: " + throwable.getMessage(), throwable);
-        }
-    }
-
-    /**
-     * Put selector to selectors map by key.
-     * @param key Selector key.
-     * @param selector Selector.
-     */
-    public static void put(String key, Selector<?, ?, ?, ?, ?> selector) {
-        selectors.put(key, new SelectorHolder(selector));
-    }
-
-    /**
-     * Put method handle selector (for named configuration) to selectors map by key.
-     * @param key Selector key.
-     * @param handle Method handle.
-     */
-    public static void put(String key, MethodHandle handle) {
-        selectors.put(key, new SelectorHolder(handle));
-    }
-
-    /**
-     * Holder for selector (it's either selector object or method handle for named configurations).
-     */
-    private static final class SelectorHolder {
-        /** Selector object. */
-        Selector<?, ?, ?, ?, ?> selector;
-
-        /** Method handle for named configuration. */
-        MethodHandle selectorFn;
-
-        /** Constructor for selector. */
-        private SelectorHolder(Selector<?, ?, ?, ?, ?> selector) {
-            this.selector = selector;
-        }
-
-        /** Constructor for method handle. */
-        private SelectorHolder(MethodHandle selectorFn) {
-            this.selectorFn = selectorFn;
-        }
-
-        /**
-         * Get selector object.
-         * @param arguments Arguments (empty if static selector or contains names for named configuration).
-         * @return Selector.
-         * @throws Throwable If failed to invoke method handle.
-         */
-        Selector<?, ?, ?, ?, ?> get(List<String> arguments) throws Throwable {
-            if (selector != null)
-                return selector;
-
-            return (Selector<?, ?, ?, ?, ?>) selectorFn.invokeWithArguments(arguments);
-        }
-
-    }
-}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/Selector.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/Selector.java
deleted file mode 100644
index ce3ed3c..0000000
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/Selector.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.internal.selector;
-
-import org.apache.ignite.configuration.internal.Modifier;
-
-/**
- * Interface for objects helping select configuration elements.
- *
- * @param <ROOT> Root configuration class.
- * @param <TARGET> Target configuration class.
- * @param <VIEW> View class of target.
- * @param <INIT> Init class of target.
- * @param <CHANGE> Change class of target.
- */
-public interface Selector<ROOT, TARGET extends Modifier<VIEW, INIT, CHANGE>, VIEW, INIT, CHANGE> {
-    /**
-     * Select configuration element.
-     *
-     * @param root Configuration root object.
-     * @return Configuration element.
-     */
-    TARGET select(ROOT root);
-}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/SelectorNotFoundException.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/SelectorNotFoundException.java
deleted file mode 100644
index 39d9381..0000000
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/SelectorNotFoundException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.ignite.configuration.internal.selector;
-
-/**
- * Exception for absence of selector.
- */
-public class SelectorNotFoundException extends RuntimeException {
-    /** Constructor. */
-    public SelectorNotFoundException(String message) {
-        super(message);
-    }
-
-    /** Constructor. */
-    public SelectorNotFoundException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/util/ConfigurationUtil.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/util/ConfigurationUtil.java
index d77a3bc..2d491b9 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/util/ConfigurationUtil.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/internal/util/ConfigurationUtil.java
@@ -18,6 +18,7 @@
 package org.apache.ignite.configuration.internal.util;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -335,6 +336,24 @@ public class ConfigurationUtil {
     }
 
     /**
+     * Creates new list that is a conjunction of given list and element.
+     *
+     * @param prefix Head of the new list.
+     * @param key Tail element of the new list.
+     * @return New list.
+     */
+    public static List<String> appendKey(List<String> prefix, String key) {
+        if (prefix.isEmpty())
+            return List.of(key);
+
+        List<String> res = new ArrayList<>(prefix.size() + 1);
+        res.addAll(prefix);
+        res.add(key);
+
+        return res;
+    }
+
+    /**
      * Apply changes on top of existing node. Creates completely new object while reusing parts of the original tree
      * that weren't modified.
      *
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConfigurationSource.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConfigurationSource.java
index b1d6e30..14507a8 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConfigurationSource.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConfigurationSource.java
@@ -27,7 +27,9 @@ public interface ConfigurationSource {
      * @param clazz Class instance of type to convert to.
      * @return Converted leaf object.
      */
-    <T> T unwrap(Class<T> clazz);
+    default <T> T unwrap(Class<T> clazz) {
+        throw new UnsupportedOperationException("unwrap");
+    }
 
     /**
      * Treats current configuration source as an inner node. Tries to construct the content of {@code node} using
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConstructableTreeNode.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConstructableTreeNode.java
index 5cad648..44b77d8 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConstructableTreeNode.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/ConstructableTreeNode.java
@@ -29,7 +29,7 @@ public interface ConstructableTreeNode {
      * @param src Source that provides data for construction.
      * @throws NoSuchElementException If {@code key} cannot be constructed.
      */
-    void construct(String key, ConfigurationSource src) throws NoSuchElementException;
+    void construct(String key,/* boolean canMutate, */ ConfigurationSource src) throws NoSuchElementException;
 
     /**
      * Public equivalent of {@link Object#clone()} method. Creates a copy with effectively the same content.
diff --git a/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/NamedListNode.java b/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/NamedListNode.java
index 41d9061..55ca78a 100644
--- a/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/NamedListNode.java
+++ b/modules/configuration/src/main/java/org/apache/ignite/configuration/tree/NamedListNode.java
@@ -28,7 +28,7 @@ import java.util.function.Supplier;
 /** */
 public final class NamedListNode<N extends InnerNode> implements NamedListView<N>, NamedListChange<N, N>, TraversableTreeNode, ConstructableTreeNode {
     /** */
-    private final Supplier<N> valSupplier;
+    public final Supplier<N> valSupplier;
 
     /** */
     private final Map<String, N> map;
diff --git a/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ITScaleCubeNetworkClusterMessagingTest.java b/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ITScaleCubeNetworkClusterMessagingTest.java
index 1f571d0..89e6376 100644
--- a/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ITScaleCubeNetworkClusterMessagingTest.java
+++ b/modules/network/src/integrationTest/java/org/apache/ignite/network/scalecube/ITScaleCubeNetworkClusterMessagingTest.java
@@ -20,12 +20,13 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Queue;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import org.apache.ignite.network.MessageHandlerHolder;
 import org.apache.ignite.network.NetworkCluster;
+import org.apache.ignite.network.NetworkClusterFactory;
 import org.apache.ignite.network.NetworkMember;
 import org.apache.ignite.network.NetworkMessage;
-import org.apache.ignite.network.MessageHandlerHolder;
-import org.apache.ignite.network.NetworkClusterFactory;
 import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -50,6 +51,7 @@ class ITScaleCubeNetworkClusterMessagingTest {
 
     /** */
     @Test
+    @Disabled
     public void messageWasSentToAllMembersSuccessfully() {
         //Given: Three started member which are gathered to cluster.
         List<String> addresses = List.of("localhost:3344", "localhost:3345", "localhost:3346");
diff --git a/modules/rest/src/main/java/org/apache/ignite/rest/RestModule.java b/modules/rest/src/main/java/org/apache/ignite/rest/RestModule.java
index a00e217..c3a8326 100644
--- a/modules/rest/src/main/java/org/apache/ignite/rest/RestModule.java
+++ b/modules/rest/src/main/java/org/apache/ignite/rest/RestModule.java
@@ -20,13 +20,10 @@ package org.apache.ignite.rest;
 import com.google.gson.JsonSyntaxException;
 import io.javalin.Javalin;
 import java.io.Reader;
+import java.util.Collections;
 import org.apache.ignite.configuration.ConfigurationRegistry;
-import org.apache.ignite.configuration.Configurator;
-import org.apache.ignite.configuration.internal.selector.SelectorNotFoundException;
 import org.apache.ignite.configuration.validation.ConfigurationValidationException;
-import org.apache.ignite.rest.configuration.InitRest;
 import org.apache.ignite.rest.configuration.RestConfigurationImpl;
-import org.apache.ignite.rest.configuration.Selectors;
 import org.apache.ignite.rest.presentation.ConfigurationPresentation;
 import org.apache.ignite.rest.presentation.FormatConverter;
 import org.apache.ignite.rest.presentation.json.JsonConverter;
@@ -65,23 +62,16 @@ public class RestModule {
 
     /** */
     public void prepareStart(ConfigurationRegistry sysConfig, Reader moduleConfReader) {
-        try {
-            Class.forName(Selectors.class.getName());
-        }
-        catch (ClassNotFoundException e) {
-            // No-op.
-        }
-
         sysConf = sysConfig;
 
-        presentation = new JsonPresentation(sysConfig.getConfigurators());
-
-        FormatConverter converter = new JsonConverter();
-
-        Configurator<RestConfigurationImpl> restConf = Configurator.create(RestConfigurationImpl::new,
-            converter.convertFrom(moduleConfReader, "rest", InitRest.class));
+        presentation = new JsonPresentation(Collections.emptyMap());
 
-        sysConfig.registerConfigurator(restConf);
+//        FormatConverter converter = new JsonConverter();
+//
+//        Configurator<RestConfigurationImpl> restConf = Configurator.create(RestConfigurationImpl::new,
+//            converter.convertFrom(moduleConfReader, "rest", InitRest.class));
+//
+//        sysConfig.registerConfigurator(restConf);
     }
 
     /** */
@@ -100,7 +90,7 @@ public class RestModule {
             try {
                 ctx.result(presentation.representByPath(configPath));
             }
-            catch (SelectorNotFoundException | IllegalArgumentException pathE) {
+            catch (IllegalArgumentException pathE) {
                 ErrorResult eRes = new ErrorResult("CONFIG_PATH_UNRECOGNIZED", pathE.getMessage());
 
                 ctx.status(400).result(converter.convertTo("error", eRes));
@@ -111,7 +101,7 @@ public class RestModule {
             try {
                 presentation.update(ctx.body());
             }
-            catch (SelectorNotFoundException | IllegalArgumentException argE) {
+            catch (IllegalArgumentException argE) {
                 ErrorResult eRes = new ErrorResult("CONFIG_PATH_UNRECOGNIZED", argE.getMessage());
 
                 ctx.status(400).result(converter.convertTo("error", eRes));
diff --git a/modules/rest/src/main/java/org/apache/ignite/rest/presentation/json/JsonPresentation.java b/modules/rest/src/main/java/org/apache/ignite/rest/presentation/json/JsonPresentation.java
index 1d54253..15b46fe 100644
--- a/modules/rest/src/main/java/org/apache/ignite/rest/presentation/json/JsonPresentation.java
+++ b/modules/rest/src/main/java/org/apache/ignite/rest/presentation/json/JsonPresentation.java
@@ -19,10 +19,8 @@ package org.apache.ignite.rest.presentation.json;
 
 import java.util.Map;
 import java.util.stream.Collectors;
-import org.apache.ignite.configuration.ConfigurationProperty;
 import org.apache.ignite.configuration.Configurator;
 import org.apache.ignite.configuration.internal.DynamicConfiguration;
-import org.apache.ignite.configuration.internal.selector.BaseSelectors;
 import org.apache.ignite.rest.presentation.ConfigurationPresentation;
 
 /** */
@@ -53,13 +51,14 @@ public class JsonPresentation implements ConfigurationPresentation<String> {
         if (path == null || path.isEmpty())
             return represent();
 
-        String root = path.contains(".") ? path.substring(0, path.indexOf('.')) : path;
-
-        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator = configsMap.get(root);
-
-        ConfigurationProperty<Object, Object> prop = configurator.getInternal(BaseSelectors.find(path));
-
-        return converter.convertTo(prop.value());
+//        String root = path.contains(".") ? path.substring(0, path.indexOf('.')) : path;
+//
+//        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator = configsMap.get(root);
+//
+//        ConfigurationProperty<Object, Object> prop = configurator.getInternal(BaseSelectors.find(path));
+//
+//        return converter.convertTo(prop.value());
+        return "";
     }
 
     /** {@inheritDoc} */
@@ -76,8 +75,8 @@ public class JsonPresentation implements ConfigurationPresentation<String> {
             throw new IllegalArgumentException("Invalid request, configuration root not found: " + configUpdate);
         }
 
-        Object updateObj = converter.convertFrom(configUpdate, root, configurator.getChangeType());
+//        Object updateObj = converter.convertFrom(configUpdate, root, configurator.getChangeType());
 
-        configurator.set(BaseSelectors.find(root), updateObj);
+//        configurator.set(BaseSelectors.find(root), updateObj);
     }
 }
diff --git a/modules/runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java b/modules/runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java
index fb222ca..1847d6f 100644
--- a/modules/runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java
+++ b/modules/runner/src/main/java/org/apache/ignite/configuration/ConfigurationModule.java
@@ -18,11 +18,6 @@
 package org.apache.ignite.configuration;
 
 import java.io.Reader;
-import org.apache.ignite.configuration.extended.InitLocal;
-import org.apache.ignite.configuration.extended.LocalConfigurationImpl;
-import org.apache.ignite.configuration.extended.Selectors;
-import org.apache.ignite.rest.presentation.FormatConverter;
-import org.apache.ignite.rest.presentation.json.JsonConverter;
 
 /**
  * Module is responsible for preparing configuration when module is started.
@@ -31,36 +26,20 @@ import org.apache.ignite.rest.presentation.json.JsonConverter;
  * {@link Configurator} object.
  */
 public class ConfigurationModule {
-    static {
-        try {
-            Selectors.LOCAL_BASELINE.select(null);
-        }
-        catch (Throwable ignored) {
-            // No-op.
-        }
-    }
-
-    /** */
-    private Configurator<LocalConfigurationImpl> localConfigurator;
+//    /** */
+//    private Configurator<LocalConfigurationImpl> localConfigurator;
 
     /** */
     private final ConfigurationRegistry confRegistry = new ConfigurationRegistry();
 
     /** */
     public void bootstrap(Reader confReader) {
-        FormatConverter converter = new JsonConverter();
-
-        Configurator<LocalConfigurationImpl> configurator =
-            Configurator.create(LocalConfigurationImpl::new, converter.convertFrom(confReader, "local", InitLocal.class));
-
-        localConfigurator = configurator;
-
-        confRegistry.registerConfigurator(configurator);
-    }
-
-    /** */
-    public Configurator<LocalConfigurationImpl> localConfigurator() {
-        return localConfigurator;
+//        FormatConverter converter = new JsonConverter();
+//
+//        Configurator<LocalConfigurationImpl> configurator =
+//            Configurator.create(LocalConfigurationImpl::new, converter.convertFrom(confReader, "local", InitLocal.class));
+//
+//        confRegistry.registerConfigurator(configurator);
     }
 
     /** */