diff --git a/core/config/schema/core.data_types.schema.yml b/core/config/schema/core.data_types.schema.yml
index 2b86cd7..f20d0e4 100644
--- a/core/config/schema/core.data_types.schema.yml
+++ b/core/config/schema/core.data_types.schema.yml
@@ -42,12 +42,14 @@ uri:
 mapping:
   label: Mapping
   class: '\Drupal\Core\Config\Schema\Mapping'
+  definition_class: '\Drupal\Core\TypedData\MapDataDefinition'
 sequence:
   label: Sequence
   class: '\Drupal\Core\Config\Schema\Sequence'
-
+  definition_class: '\Drupal\Core\TypedData\ListDataDefinition'
+  
 # Simple extended data types:
-
+ 
 # Human readable string that must be plain text and editable with a text field.
 label:
   type: string
diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php
index 2563ec5..c492d42 100644
--- a/core/lib/Drupal/Core/Config/Schema/Element.php
+++ b/core/lib/Drupal/Core/Config/Schema/Element.php
@@ -28,4 +28,13 @@ protected function parseElement($key, $data, $definition) {
     return \Drupal::service('config.typed')->create($definition, $data, $key, $this);
   }
 
+  /**
+   * Build data definition object for contained elements.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinitionInterface
+   */
+  protected function buildDataDefinition($definition, $value, $key) {
+    return  \Drupal::service('config.typed')->buildDataDefinition($definition, $value, $key, $this);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
index 19fb596..5729390 100644
--- a/core/lib/Drupal/Core/Config/Schema/Mapping.php
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -20,11 +20,20 @@
 class Mapping extends ArrayElement implements ComplexDataInterface {
 
   /**
+   * An array of data definitions.
+   *
+   * @var \Drupal\Core\TypedData\DataDefinitionInterface[]
+   */
+  protected $propertyDefinitions;
+
+  /**
    * Overrides ArrayElement::parse()
+   *
+   * Note this only returns elements that have a data definition.
    */
   protected function parse() {
     $elements = array();
-    foreach ($this->definition['mapping'] as $key => $definition) {
+    foreach ($this->getPropertyDefinitions() as $key => $definition) {
       if (isset($this->value[$key]) || array_key_exists($key, $this->value)) {
         $elements[$key] = $this->parseElement($key, $this->value[$key], $definition);
       }
@@ -103,13 +112,12 @@ public function toArray() {
    * @param string $name
    *   The name of property.
    *
-   * @return array|null
+   * @return \Drupal\Core\TypedData\DataDefinitionInterface|null
    *   The definition of the property or NULL if the property does not exist.
    */
   public function getPropertyDefinition($name) {
-    if (isset($this->definition['mapping'][$name])) {
-      return $this->definition['mapping'][$name];
-    }
+    $definitions = $this->getPropertyDefinitions();
+    return isset($definitions[$name]) ? isset($definitions[$name]) : NULL;
   }
 
   /**
@@ -120,11 +128,14 @@ public function getPropertyDefinition($name) {
    *   property name.
    */
   public function getPropertyDefinitions() {
-    $list = array();
-    foreach ($this->getAllKeys() as $key) {
-      $list[$key] = $this->getPropertyDefinition($key);
+    if (!isset($this->propertyDefinitions)) {
+      $this->propertyDefinitions = array();
+      foreach ($this->definition['mapping'] as $key => $definition) {
+        $value = isset($this->value[$key]) ? $this->value[$key] : NULL;
+        $this->propertyDefinitions[$key] = $this->buildDataDefinition($definition, $value, $key);
+      }
     }
-    return $list;
+    return $this->propertyDefinitions;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php
index 720b850..ed82d74 100644
--- a/core/lib/Drupal/Core/Config/Schema/Sequence.php
+++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php
@@ -15,13 +15,22 @@
 class Sequence extends ArrayElement implements ListInterface {
 
   /**
+   * Data definition
+   *
+   * @var \Drupal\Core\TypedData\DataDefinitionInterface
+   */
+  protected $itemDefinition;
+
+  /**
    * Overrides ArrayElement::parse()
    */
   protected function parse() {
-    $definition = $this->getItemDefinition();
+    // Get the generic definition and reprocess it for all items.
+    $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array();
     $elements = array();
     foreach ($this->value as $key => $value) {
-      $elements[$key] = $this->parseElement($key, $value, $definition);
+      $data_definition =  $this->buildDataDefinition($definition, $value, $key);
+      $elements[$key] = $this->parseElement($key, $value, $data_definition);
     }
     return $elements;
   }
@@ -37,7 +46,11 @@ public function isEmpty() {
    * Implements Drupal\Core\TypedData\ListInterface::getItemDefinition().
    */
   public function getItemDefinition() {
-    return $this->definition['sequence'][0];
+    if (!isset($this->itemDefinition)) {
+      $definition = isset($this->definition['sequence'][0]) ? $this->definition['sequence'][0] : array();
+      $this->itemDefinition = $this->buildDataDefinition($definition, NULL);
+    }
+    return $this->itemDefinition;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/StorableConfigBase.php b/core/lib/Drupal/Core/Config/StorableConfigBase.php
index 4a5fd1d..8151e4f 100644
--- a/core/lib/Drupal/Core/Config/StorableConfigBase.php
+++ b/core/lib/Drupal/Core/Config/StorableConfigBase.php
@@ -128,7 +128,8 @@ public function getStorage() {
   protected function getSchemaWrapper() {
     if (!isset($this->schemaWrapper)) {
       $definition = $this->typedConfigManager->getDefinition($this->name);
-      $this->schemaWrapper = $this->typedConfigManager->create($definition, $this->data);
+      $data_definition = $this->typedConfigManager->buildDataDefinition($definition, $this->data);
+      $this->schemaWrapper = $this->typedConfigManager->create($data_definition, $this->data);
     }
     return $this->schemaWrapper;
   }
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
index 2032f4c..938593c 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManager.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -12,11 +12,17 @@
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Component\Utility\String;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\TypedData\DataDefinitionInterface;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\ListDataDefinition;
+use Drupal\Core\TypedData\ListDataDefinitionInterface;
+use Drupal\Core\TypedData\MapDataDefinition;
+use Drupal\Core\TypedData\TypedDataManager;
 
 /**
  * Manages config type plugins.
  */
-class TypedConfigManager extends PluginManagerBase implements TypedConfigManagerInterface {
+class TypedConfigManager extends TypedDataManager implements TypedConfigManagerInterface {
 
   /**
    * The cache ID for the definitions.
@@ -80,19 +86,19 @@ public function __construct(StorageInterface $configStorage, StorageInterface $s
    */
   public function get($name) {
     $data = $this->configStorage->read($name);
-    $definition = $this->getDefinition($name);
-    return $this->create($definition, $data);
+    $type_definition = $this->getDefinition($name);
+    $data_definition =  $this->buildDataDefinition($type_definition, $data);
+    return $this->create($data_definition, $data);
   }
 
   /**
    * {@inheritdoc}
    */
-  public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL) {
-    if (!isset($definition['type'])) {
-      // By default elements without a type are undefined.
-      $definition['type'] = 'undefined';
-    }
-    elseif (strpos($definition['type'], ']')) {
+  public function buildDataDefinition(array $definition, $value, $name = NULL, $parent = NULL) {
+    // Add default values for data type and replace variables.
+    $definition += array('type' => 'undefined');
+
+    if (strpos($definition['type'], ']')) {
       // Replace variable names in definition.
       $replace = is_array($value) ? $value : array();
       if (isset($parent)) {
@@ -103,45 +109,18 @@ public function create(array $definition, $value = NULL, $name = NULL, $parent =
       }
       $definition['type'] = $this->replaceName($definition['type'], $replace);
     }
-    // Create typed config object.
-    $wrapper = $this->createInstance($definition['type'], array(
-      'data_definition' => $definition,
-      'name' => $name,
-      'parent' => $parent,
-    ));
-    if (isset($value)) {
-      $wrapper->setValue($value, FALSE);
-    }
-    return $wrapper;
-  }
+    // Add default values from type definition.
+    $definition += $this->getDefinition($definition['type']);
 
-  /**
-   * {@inheritdoc}
-   */
-  public function createInstance($data_type, array $configuration = array()) {
-    $data_definition = $configuration['data_definition'];
-    $type_definition = $this->getDefinition($data_type);
+    $data_definition = $this->createDataDefinition($definition['type']);
 
-    if (!isset($type_definition)) {
-      throw new \InvalidArgumentException(String::format('Invalid data type %plugin_id has been given.', array('%plugin_id' => $data_type)));
-    }
-
-    // Allow per-data definition overrides of the used classes, i.e. take over
-    // classes specified in the type definition.
-    $data_definition += $type_definition;
-
-    $key = empty($data_definition['list']) ? 'class' : 'list class';
-    if (isset($data_definition[$key])) {
-      $class = $data_definition[$key];
-    }
-    elseif (isset($type_definition[$key])) {
-      $class = $type_definition[$key];
-    }
-
-    if (!isset($class)) {
-      throw new PluginException(sprintf('The plugin (%s) did not specify an instance class.', $data_type));
+    // Pass remaining values from definition array to data definition.
+    foreach ($definition as $key => $value) {
+      if (!isset($data_definition[$key])) {
+        $data_definition[$key] = $value;
+      }
     }
-    return new $class($data_definition, $configuration['name'], $configuration['parent']);
+    return $data_definition;
   }
 
   /**
@@ -169,7 +148,11 @@ public function getDefinition($base_plugin_id, $exception_on_invalid = TRUE) {
       unset($definition['type']);
       $this->definitions[$type] = $definition;
     }
-    return $definition;
+    // Add type and default definition class.
+    return $definition + array(
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
+      'type' => $type,
+    );
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php
index 827363f..f475c02 100644
--- a/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php
+++ b/core/lib/Drupal/Core/Config/TypedConfigManagerInterface.php
@@ -9,6 +9,7 @@
 
 use Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface;
 use Drupal\Component\Plugin\PluginManagerInterface;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Defines an interface for typed configuration manager.
@@ -36,7 +37,8 @@ public function get($name);
    *   instantiated.
    * @param array $configuration
    *   The plugin configuration array, i.e. an array with the following keys:
-   *   - data definition: The data definition array.
+   *   - data definition: The data definition object, i.e. an instance of
+   *     \Drupal\Core\TypedData\DataDefinitionInterface.
    *   - name: (optional) If a property or list item is to be created, the name
    *     of the property or the delta of the list item.
    *   - parent: (optional) If a property or list item is to be created, the
@@ -51,10 +53,10 @@ public function createInstance($data_type, array $configuration = array());
   /**
    * Creates a new typed configuration object instance.
    *
-   * @param array $definition
-   *   The data definition of the typed data object
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
+   *   The data definition of the typed data object.
    * @param mixed $value
-   *   (optional) The data value. If set, it has to match one of the supported
+   *   The data value. If set, it has to match one of the supported
    *   data type format as documented for the data type classes.
    * @param string $name
    *   (optional) If a property or list item is to be created, the name of the
@@ -67,7 +69,27 @@ public function createInstance($data_type, array $configuration = array());
    * @return \Drupal\Core\Config\Schema\Element
    *   The instantiated typed data object.
    */
-  public function create(array $definition, $value = NULL, $name = NULL, $parent = NULL);
+  public function create(DataDefinitionInterface $definition, $value, $name = NULL, $parent = NULL);
+
+  /**
+   * Creates a new data definition object from a type definition array and
+   * actual configuration data. Since type definitions may contain variables
+   * to be replaced, we need the configuration value to create it.
+   *
+   * @param array $definition
+   *   The base type definition array, for which a data definition should be
+   *   created.
+   * @param $value
+   *   Optional value of the configuraiton element.
+   * @param string $name
+   *   Optional name of the configuration element.
+   * @param object $parent
+   *   Optional parent element.
+   *
+   * @return \Drupal\Core\TypedData\DataDefinitionInterface
+   *   A data definition for the given data type.
+   */
+  public function buildDataDefinition(array $definition, $value, $name = NULL, $parent = NULL);
 
   /**
    * Checks if the configuration schema with the given config name exists.
diff --git a/core/modules/config/src/Tests/ConfigSchemaTest.php b/core/modules/config/src/Tests/ConfigSchemaTest.php
index 14161bb..cef3d0d 100644
--- a/core/modules/config/src/Tests/ConfigSchemaTest.php
+++ b/core/modules/config/src/Tests/ConfigSchemaTest.php
@@ -48,6 +48,8 @@ function testSchemaMapping() {
     $expected = array();
     $expected['label'] = 'Undefined';
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
+    $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for nonexistent configuration.');
 
     // Configuration file without schema will return Undefined as well.
@@ -63,21 +65,25 @@ function testSchemaMapping() {
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
     $expected['mapping']['testitem'] = array('label' => 'Test item');
     $expected['mapping']['testlist'] = array('label' => 'Test list');
+    $expected['type'] = 'config_schema_test.someschema';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for configuration with only some schema.');
 
     // Check type detection on elements with undefined types.
     $config = \Drupal::service('config.typed')->get('config_schema_test.someschema');
-    $definition = $config['testitem']->getDataDefinition();
+    $definition = $config['testitem']->getDataDefinition()->toArray();
     $expected = array();
     $expected['label'] = 'Test item';
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
     $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
     $this->assertEqual($definition, $expected, 'Automatic type detected for a scalar is undefined.');
-    $definition = $config['testlist']->getDataDefinition();
+    $definition = $config['testlist']->getDataDefinition()->toArray();
     $expected = array();
     $expected['label'] = 'Test list';
     $expected['class'] = '\Drupal\Core\Config\Schema\Undefined';
     $expected['type'] = 'undefined';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
     $this->assertEqual($definition, $expected, 'Automatic type detected for a list is undefined.');
 
     // Simple case, straight metadata.
@@ -93,6 +99,8 @@ function testSchemaMapping() {
       'label' => 'Default language',
       'type' => 'string',
     );
+    $expected['type'] = 'system.maintenance';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance');
 
     // Mixed schema with ignore elements.
@@ -100,6 +108,7 @@ function testSchemaMapping() {
     $expected = array();
     $expected['label'] = 'Ignore test';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['mapping']['label'] = array(
       'label' =>  'Label',
       'type' => 'label',
@@ -116,16 +125,19 @@ function testSchemaMapping() {
       'label' => 'Weight',
       'type' => 'integer',
     );
+    $expected['type'] = 'config_schema_test.ignore';
+
     $this->assertEqual($definition, $expected);
 
     // The ignore elements themselves.
-    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition();
+    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('irrelevant')->getDataDefinition()->toArray();
     $expected = array();
     $expected['type'] = 'ignore';
     $expected['label'] = 'Irrelevant';
     $expected['class'] = '\Drupal\Core\Config\Schema\Ignore';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\DataDefinition';
     $this->assertEqual($definition, $expected);
-    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition();
+    $definition = \Drupal::service('config.typed')->get('config_schema_test.ignore')->get('indescribable')->getDataDefinition()->toArray();
     $expected['label'] = 'Indescribable';
     $this->assertEqual($definition, $expected);
 
@@ -134,6 +146,7 @@ function testSchemaMapping() {
     $expected = array();
     $expected['label'] = 'Image style';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['mapping']['name']['type'] = 'string';
     $expected['mapping']['id']['label'] = 'ID';
     $expected['mapping']['id']['type'] = 'string';
@@ -154,6 +167,7 @@ function testSchemaMapping() {
     $expected['mapping']['effects']['sequence'][0]['mapping']['data']['type'] = 'image.effect.[%parent.id]';
     $expected['mapping']['effects']['sequence'][0]['mapping']['weight']['type'] = 'integer';
     $expected['mapping']['effects']['sequence'][0]['mapping']['uuid']['type'] = 'string';
+    $expected['type'] = 'image.style.*';
 
     $this->assertEqual($definition, $expected);
 
@@ -163,18 +177,21 @@ function testSchemaMapping() {
     $expected = array();
     $expected['label'] = 'Image scale';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['mapping']['width']['type'] = 'integer';
     $expected['mapping']['width']['label'] = 'Width';
     $expected['mapping']['height']['type'] = 'integer';
     $expected['mapping']['height']['label'] = 'Height';
     $expected['mapping']['upscale']['type'] = 'boolean';
     $expected['mapping']['upscale']['label'] = 'Upscale';
+    $expected['type'] = 'image.effect.image_scale';
+
 
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.effect.image_scale');
 
     // Most complex case, get metadata for actual configuration element.
     $effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects');
-    $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDataDefinition();
+    $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDataDefinition()->toArray();
     // This should be the schema for image.effect.image_scale, reuse previous one.
     $expected['type'] =  'image.effect.image_scale';
 
@@ -190,6 +207,8 @@ function testSchemaMapping() {
     $expected['mapping']['testid']['label'] = 'ID';
     $expected['mapping']['testdescription']['type'] = 'text';
     $expected['mapping']['testdescription']['label'] = 'Description';
+    $expected['type'] = 'config_schema_test.someschema.somemodule.*.*';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
 
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.someschema.somemodule.section_one.subsection');
 
@@ -206,31 +225,34 @@ function testSchemaMappingWithParents() {
 
     // Test fetching parent one level up.
     $entry = $config_data->get('one_level');
-    $definition = $entry['testitem']->getDataDefinition();
+    $definition = $entry['testitem']->getDataDefinition()->toArray();
     $expected = array(
       'type' => 'config_schema_test.someschema.with_parents.key_1',
       'label' => 'Test item nested one level',
       'class' => '\Drupal\Core\TypedData\Plugin\DataType\String',
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
     );
     $this->assertEqual($definition, $expected);
 
     // Test fetching parent two levels up.
     $entry = $config_data->get('two_levels');
-    $definition = $entry['wrapper']['testitem']->getDataDefinition();
+    $definition = $entry['wrapper']['testitem']->getDataDefinition()->toArray();
     $expected = array(
       'type' => 'config_schema_test.someschema.with_parents.key_2',
       'label' => 'Test item nested two levels',
       'class' => '\Drupal\Core\TypedData\Plugin\DataType\String',
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
     );
     $this->assertEqual($definition, $expected);
 
     // Test fetching parent three levels up.
     $entry = $config_data->get('three_levels');
-    $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDataDefinition();
+    $definition = $entry['wrapper_1']['wrapper_2']['testitem']->getDataDefinition()->toArray();
     $expected = array(
       'type' => 'config_schema_test.someschema.with_parents.key_3',
       'label' => 'Test item nested three levels',
       'class' => '\Drupal\Core\TypedData\Plugin\DataType\String',
+      'definition_class' => '\Drupal\Core\TypedData\DataDefinition',
     );
     $this->assertEqual($definition, $expected);
   }
@@ -361,10 +383,12 @@ function testSchemaFallback() {
     $expected = array();
     $expected['label'] = 'Schema wildcard fallback test';
     $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['definition_class'] = '\Drupal\Core\TypedData\MapDataDefinition';
     $expected['mapping']['testid']['type'] = 'string';
     $expected['mapping']['testid']['label'] = 'ID';
     $expected['mapping']['testdescription']['type'] = 'text';
     $expected['mapping']['testdescription']['label'] = 'Description';
+    $expected['type'] = 'config_schema_test.wildcard_fallback.*';
 
     $this->assertEqual($definition, $expected, 'Retrieved the right metadata for config_schema_test.wildcard_fallback.something');
 
diff --git a/core/modules/config/src/Tests/ConfigSchemaTestBase.php b/core/modules/config/src/Tests/ConfigSchemaTestBase.php
index eac1a75..6c763d4 100644
--- a/core/modules/config/src/Tests/ConfigSchemaTestBase.php
+++ b/core/modules/config/src/Tests/ConfigSchemaTestBase.php
@@ -61,7 +61,8 @@ public function assertConfigSchema(TypedConfigManagerInterface $typed_config, $c
       return;
     }
     $definition = $typed_config->getDefinition($config_name);
-    $this->schema = $typed_config->create($definition, $config_data);
+    $data_definition = $typed_config->buildDataDefinition($definition, $config_data);
+    $this->schema = $typed_config->create($data_definition, $config_data);
     $this->configPass = TRUE;
     foreach ($config_data as $key => $value) {
       $this->checkValue($key, $value);
diff --git a/core/modules/config_translation/src/ConfigMapperManager.php b/core/modules/config_translation/src/ConfigMapperManager.php
index 04e1507..1e4273c 100644
--- a/core/modules/config_translation/src/ConfigMapperManager.php
+++ b/core/modules/config_translation/src/ConfigMapperManager.php
@@ -129,6 +129,13 @@ public function processDefinition(&$definition, $plugin_id) {
   /**
    * {@inheritdoc}
    */
+  public function buildDataDefinition(array $definition, $value = NULL, $name = NULL, $parent = NULL) {
+    return $this->typedConfigManager->buildDataDefinition($definition, $value, $name, $parent);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   protected function findDefinitions() {
     $definitions = $this->discovery->getDefinitions();
     foreach ($definitions as $plugin_id => &$definition) {
diff --git a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
index 921e704..26cf8b0 100644
--- a/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
+++ b/core/modules/config_translation/src/Form/ConfigTranslationFormBase.php
@@ -272,7 +272,10 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d
     foreach ($schema as $key => $element) {
       // Make the specific element key, "$base_key.$key".
       $element_key = implode('.', array_filter(array($base_key, $key)));
-      $definition = $element->getDataDefinition() + array('label' => $this->t('N/A'));
+      $definition = $element->getDataDefinition();
+      if (!$definition->getLabel()) {
+        $definition->setLabel($this->t('N/A'));
+      }
       if ($element instanceof Element) {
         // Build sub-structure and include it with a wrapper in the form
         // if there are any translatable elements there.
@@ -336,7 +339,9 @@ protected function buildConfigForm(Element $schema, $config_data, $base_config_d
           '#type' => 'item',
         );
 
-        $definition += array('form_element_class' => '\Drupal\config_translation\FormElement\Textfield');
+        if (!isset($definition['form_element_class'])) {
+          $definition['form_element_class'] = '\Drupal\config_translation\FormElement\Textfield';
+        }
 
         /** @var \Drupal\config_translation\FormElement\ElementInterface $form_element */
         $form_element = new $definition['form_element_class']();
diff --git a/core/modules/config_translation/src/FormElement/DateFormat.php b/core/modules/config_translation/src/FormElement/DateFormat.php
index 762968b..b9d4973 100644
--- a/core/modules/config_translation/src/FormElement/DateFormat.php
+++ b/core/modules/config_translation/src/FormElement/DateFormat.php
@@ -12,6 +12,7 @@
 use Drupal\Core\Ajax\ReplaceCommand;
 use Drupal\Core\Language\Language;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Defines the date format element for the configuration translation interface.
@@ -22,7 +23,7 @@ class DateFormat implements ElementInterface {
   /**
    * {@inheritdoc}
    */
-  public function getFormElement(array $definition, Language $language, $value) {
+  public function getFormElement(DataDefinitionInterface $definition, Language $language, $value) {
     $description = $this->t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://php.net/manual/function.date.php'));
     $format = $this->t('Displayed as %date_format', array('%date_format' => \Drupal::service('date')->format(REQUEST_TIME, 'custom', $value)));
     return array(
diff --git a/core/modules/config_translation/src/FormElement/ElementInterface.php b/core/modules/config_translation/src/FormElement/ElementInterface.php
index 9072cfc..5ea9420 100644
--- a/core/modules/config_translation/src/FormElement/ElementInterface.php
+++ b/core/modules/config_translation/src/FormElement/ElementInterface.php
@@ -8,6 +8,7 @@
 namespace Drupal\config_translation\FormElement;
 
 use Drupal\Core\Language\Language;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Provides an interface for configuration translation form elements.
@@ -17,7 +18,7 @@
   /**
    * Returns the translation form element for a given configuration definition.
    *
-   * @param array $definition
+   * @param \Drupal\Core\TypedData\DataDefinitionInterface $definition
    *   Configuration schema type definition of the element.
    * @param \Drupal\Core\Language\Language $language
    *   Language object to display the translation form for.
@@ -27,6 +28,6 @@
    * @return array
    *   Form API array to represent the form element.
    */
-  public function getFormElement(array $definition, Language $language, $value);
+  public function getFormElement(DataDefinitionInterface $definition, Language $language, $value);
 
 }
diff --git a/core/modules/config_translation/src/FormElement/Textarea.php b/core/modules/config_translation/src/FormElement/Textarea.php
index b796685..f36c467 100644
--- a/core/modules/config_translation/src/FormElement/Textarea.php
+++ b/core/modules/config_translation/src/FormElement/Textarea.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Defines the textarea element for the configuration translation interface.
@@ -19,7 +20,7 @@ class Textarea implements ElementInterface {
   /**
    * {@inheritdoc}
    */
-  public function getFormElement(array $definition, Language $language, $value) {
+  public function getFormElement(DataDefinitionInterface $definition, Language $language, $value) {
     // Estimate a comfortable size of the input textarea.
     $rows_words = ceil(str_word_count($value) / 5);
     $rows_newlines = substr_count($value, "\n" ) + 1;
diff --git a/core/modules/config_translation/src/FormElement/Textfield.php b/core/modules/config_translation/src/FormElement/Textfield.php
index 46d71fe..e2015b6 100644
--- a/core/modules/config_translation/src/FormElement/Textfield.php
+++ b/core/modules/config_translation/src/FormElement/Textfield.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Defines the textfield element for the configuration translation interface.
@@ -19,7 +20,7 @@ class Textfield implements ElementInterface {
   /**
    * {@inheritdoc}
    */
-  public function getFormElement(array $definition, Language $language, $value) {
+  public function getFormElement(DataDefinitionInterface $definition, Language $language, $value) {
     return array(
       '#type' => 'textfield',
       '#default_value' => $value,
diff --git a/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php b/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php
index 8a55f2d..648163e 100644
--- a/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php
+++ b/core/modules/config_translation/tests/src/ConfigMapperManagerTest.php
@@ -11,6 +11,8 @@
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Tests\UnitTestCase;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 
 /**
  * Tests ConfigMapperManager.
@@ -161,10 +163,11 @@ public function providerTestHasTranslatable() {
    *   The mocked schema element.
    */
   protected function getElement(array $definition) {
+    $data_definition = new DataDefinition($definition);
     $element = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
     $element->expects($this->any())
       ->method('getDataDefinition')
-      ->will($this->returnValue($definition));
+      ->will($this->returnValue($data_definition));
     return $element;
   }
 
diff --git a/core/modules/locale/src/LocaleConfigManager.php b/core/modules/locale/src/LocaleConfigManager.php
index 5b0aa4e..a6bc965 100644
--- a/core/modules/locale/src/LocaleConfigManager.php
+++ b/core/modules/locale/src/LocaleConfigManager.php
@@ -96,9 +96,10 @@ public function get($name) {
     // We get only the data that didn't change from default.
     $data = $this->compareConfigData($default, $updated);
     $definition = $this->getDefinition($name);
+    $data_definition = $this->buildDataDefinition($definition, $data);
     // Unless the configuration has a explicit language code we assume English.
     $langcode = isset($default['langcode']) ? $default['langcode'] : 'en';
-    $wrapper = new LocaleTypedConfig($definition, $name, $langcode, $this);
+    $wrapper = new LocaleTypedConfig($data_definition, $name, $langcode, $this);
     $wrapper->setValue($data);
     return $wrapper;
   }
diff --git a/core/modules/locale/src/LocaleTypedConfig.php b/core/modules/locale/src/LocaleTypedConfig.php
index c0095f1..8980e73 100644
--- a/core/modules/locale/src/LocaleTypedConfig.php
+++ b/core/modules/locale/src/LocaleTypedConfig.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\ContextAwareInterface;
+use Drupal\Core\TypedData\DataDefinitionInterface;
 use Drupal\Core\Config\Schema\Element;
 use Drupal\Core\Config\Schema\ArrayElement;
 
@@ -50,7 +51,7 @@ class LocaleTypedConfig extends Element {
    * @param \Drupal\locale\LocaleConfigManager $localeConfig;
    *   The locale configuration manager object.
    */
-  public function __construct($definition, $name, $langcode, LocaleConfigManager $localeConfig) {
+  public function __construct(DataDefinitionInterface $definition, $name, $langcode, LocaleConfigManager $localeConfig) {
     parent::__construct($definition, $name);
     $this->langcode = $langcode;
     $this->localeConfig = $localeConfig;
