diff --git a/core/includes/common.inc b/core/includes/common.inc
index e7ebd1f..b212383 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -7064,6 +7064,84 @@ function drupal_get_updaters() {
 }
 
 /**
+ * Gets information about all data types.
+ *
+ * @see drupal_wrap_data()
+ * @see hook_data_type_info()
+ */
+function drupal_get_data_type_info() {
+  $items = &drupal_static(__FUNCTION__);
+  if (!isset($items)) {
+    $items = module_invoke_all('data_type_info');
+    drupal_alter('data_type_info', $items);
+  }
+  return $items;
+}
+
+/**
+ * Wraps a data value into a typed data wrapper.
+ *
+ * @param array $definition
+ *   The data definition array with the following array keys and values:
+ *   - type: The data type of the data to wrap. Required.
+ *   - label: A human readable label.
+ *   - description: A human readable description.
+ *   - list: Whether the wrapped data is multi-valued, i.e. a list of data
+ *     items. Defaults to FALSE.
+ *   - computed: A boolean specifying whether the data value is computed by the
+ *     wrapper, e.g. depending on some other values.
+ *   - read-only: A boolean specifying whether the wrapped data is read-only.
+ *     Defaults to TRUE for computed properties, to FALSE otherwise.
+ *   - class: If set and 'list' is FALSE, the class to use for creating the
+ *     typed data wrapper. Else the default class as specified for the data type
+ *     will be used.
+ *   - list class: If set and 'list' is TRUE, the class to use for creating the
+ *     typed data wrapper. Else the default list class as specified for the data
+ *     type will be used.
+ *   - settings: An array of settings, as required by the used class. See the
+ *     documentation of the used class for supported or required settings.
+ *   - constraints: An array of type specific value constraints, e.g. for data
+ *     of type 'entity' the 'entity type' and 'bundle' may be specified. See the
+ *     documentation of the data type class for supported constraints.
+ *   - required: A boolean specifying whether a non-NULL value is mandatory.
+ *   Further keys may be supported in certain usages, e.g. for further keys
+ *   supported for entity property definitions see
+ *   Drupal\Core\Entity\StorageControllerInterface::getPropertyDefinitions().
+ * @param mixed $value
+ *   (optional) The data value. If set, it has to match the data type format as
+ *   documented for the data type classes.
+ * @param array $context
+ *   (optional) An array describing the context of the data. It should be
+ *   passed if a data value is wrapped as part of a data structure. The
+ *   following keys are supported:
+ *   - name: The name of the data being wrapped.
+ *   - parent: The parent object containing the data. Must be an instance of
+ *     Drupal\Core\TypedData\StructureInterface or
+ *     Drupal\Core\TypedData\ListInterface.
+ *
+ * @return Drupal\Core\TypedData\WrapperInterface
+ *
+ * @see drupal_get_data_type_info()
+ * @see Drupal\Core\TypedData\Type\Integer
+ * @see Drupal\Core\TypedData\Type\Decimal
+ * @see Drupal\Core\TypedData\Type\String
+ * @see Drupal\Core\TypedData\Type\Boolean
+ * @see Drupal\Core\TypedData\Type\Duration
+ * @see Drupal\Core\TypedData\Type\Date
+ * @see Drupal\Core\TypedData\Type\Uri
+ * @see Drupal\Core\TypedData\Type\Binary
+ * @see Drupal\Core\Entity\Property\EntityWrapper
+ */
+function drupal_wrap_data(array $definition, $value = NULL, array $context = array()) {
+  $type_info = drupal_get_data_type_info();
+
+  // Allow per-data definition overrides of the used classes.
+  $full_definition = $definition + $type_info[$definition['type']];
+  $class = empty($full_definition['list']) ? $full_definition['class'] : $full_definition['list class'];
+  return new $class($full_definition, $value, $context);
+}
+
+/**
  * Assembles the Drupal FileTransfer registry.
  *
  * @return
diff --git a/core/includes/config.inc b/core/includes/config.inc
index 39094f8..4abc363 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -1,6 +1,7 @@
 <?php
 
 use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigMetadata;
 use Drupal\Core\Config\FileStorage;
 use Drupal\Core\Config\NullStorage;
 use Drupal\Core\Config\StorageInterface;
@@ -104,6 +105,23 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf
 }
 
 /**
+ * Retrieves a metadata object for a configuration object or key.
+ *
+ * @param $name
+ *   The name of the configuration object for which we want to build a metadata object.
+ *
+ * @return Drupal\Core\Config\ConfigMetadata
+ *   An metadata object that contains the full metadata for the reguested name.
+ */
+function config_metadata($name) {
+  $metadata = &drupal_static(__FUNCTION__);
+  if (!$metadata) {
+    $metadata = new ConfigMetadata();
+  }
+  return $metadata[$name];
+}
+
+/**
  * Writes an array of config file changes from a source storage to a target storage.
  *
  * @param array $config_changes
diff --git a/core/lib/Drupal/Component/Utility/NestedArray.php b/core/lib/Drupal/Component/Utility/NestedArray.php
index 6617c68..09b4e2c 100644
--- a/core/lib/Drupal/Component/Utility/NestedArray.php
+++ b/core/lib/Drupal/Component/Utility/NestedArray.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Component\Utility;
 
+use Drupal\Core\TypedData\WrapperInterface;
+
 /**
  * Provides helpers to perform operations on nested arrays and array keys of variable depth.
  */
@@ -338,4 +340,166 @@ class NestedArray {
     return $result;
   }
 
+  /**
+   * Convert array into plain list.
+   *
+   * @param array $array
+   *   The array with the value to check for.
+   * @param string $prefix
+   *   Prefix to add to key names.
+   */
+  public static function toList(array $array, $prefix = '') {
+    $list = array();
+    foreach ($array as $key => $value) {
+      if (is_array($value)) {
+        $list += self::toList($value, $prefix . $key . '.');
+      }
+      else {
+        $list[$prefix . $key] = $value;
+      }
+    }
+    return $list;
+  }
+
+  /**
+   * Gets data from array using key with dot notation.
+   *
+   * @param array $array
+   *   The array from which to get the value.
+   *
+   * @param $key
+   *   A string that maps to a key within the array data.
+   *   For instance in the following array:
+   *   @code
+   *   array(
+   *     'foo' => array(
+   *       'bar' => 'baz',
+   *     ),
+   *   );
+   *   @endcode
+   *   A key of 'foo.bar' would return the string 'baz'. However, a key of 'foo'
+   *   would return array('bar' => 'baz').
+   *   If no key is specified, then the entire data array is returned.
+   */
+  public static function &getData(array &$array, $key) {
+    if (empty($key)) {
+      return $array;
+    }
+    else {
+      $null = NULL;
+      $parts = explode('.', $key);
+      if (count($parts) == 1) {
+        if (isset($array[$key])) {
+          return $array[$key];
+        }
+        else {
+          return $null;
+        }
+      }
+      else {
+        $value = NestedArray::getValue($array, $parts, $key_exists);
+        if ($key_exists) {
+          return $value;
+        }
+        else {
+          return $null;
+        }
+      }
+    }
+  }
+
+  /**
+   * Sets value in array using key with dot notation.
+   *
+   * @param array $array
+   *   The array from which to set the value.
+   * @param $key
+   *   @todo
+   * @param $value
+   *   @todo
+   */
+  public static function setData(array &$array, $key, $value) {
+    // The dot/period is a reserved character; it may appear between keys, but
+    // not within keys.
+    $parts = explode('.', $key);
+    if (count($parts) == 1) {
+      $array[$key] = $value;
+    }
+    else {
+      NestedArray::setValue($array, $parts, $value);
+    }
+  }
+
+  /**
+   * Unsets value in this config object.
+   *
+   * @param array $array
+   *   The array from which to set the value.
+   * @param $key
+   *   Name of the key whose value should be unset.
+   */
+  public static function unsetData(array &$array, $key) {
+    $parts = explode('.', $key);
+    if (count($parts) == 1) {
+      unset($array[$key]);
+    }
+    else {
+      NestedArray::unsetValue($array, $parts);
+    }
+  }
+
+  /**
+   * Sorts all keys in array.
+   *
+   * @param array $data
+   *   An associative array to sort recursively by key name.
+   */
+  public static function sortByKey(array &$data) {
+    ksort($data);
+    foreach ($data as &$value) {
+      if (is_array($value)) {
+        self::sortByKey($value);
+      }
+    }
+  }
+
+  /**
+   * Casts a value or an array of values to a string.
+   *
+   * Any non-scalar value that is not an array (aka objects) gets cast
+   * to an array, unless the object implements the WrapperInterface.
+   * In that case the getString() method is used instead.
+   *
+   * @see Drupal\Core\TypedData\WrapperInterface
+   *
+   * @param $value
+   *   A value being saved into the configuration system.
+   * @return
+   *   The value cast to a string or array of strings.
+   */
+  public static function castToStrings($value) {
+    if (is_scalar($value)) {
+      // Handle special case of FALSE, which should be '0' instead of ''.
+      if ($value === FALSE) {
+        $value = '0';
+      }
+      else {
+        $value = (string) $value;
+      }
+    }
+    elseif (is_object($value) && $value instanceof WrapperInterface) {
+      $value = $value->getString();
+    }
+    else {
+      // Any non-scalar value must be an array.
+      if (!is_array($value)) {
+        $value = (array) $value;
+      }
+      // Recurse into any nested keys.
+      foreach ($value as $key => $nested_value) {
+        $value[$key] = self::castToStrings($nested_value);
+      }
+    }
+    return $value;
+  }
 }
diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php
index 538ab6d..308b19e 100644
--- a/core/lib/Drupal/Core/Config/Config.php
+++ b/core/lib/Drupal/Core/Config/Config.php
@@ -34,7 +34,7 @@ class Config {
    *
    * @var array
    */
-  protected $data;
+  protected $data = array();
 
   /**
    * The overridden data of the configuration object.
@@ -142,19 +142,7 @@ class Config {
     if (!isset($this->overriddenData)) {
       $this->setOverriddenData();
     }
-    if (empty($key)) {
-      return $this->overriddenData;
-    }
-    else {
-      $parts = explode('.', $key);
-      if (count($parts) == 1) {
-        return isset($this->overriddenData[$key]) ? $this->overriddenData[$key] : NULL;
-      }
-      else {
-        $value = NestedArray::getValue($this->overriddenData, $parts, $key_exists);
-        return $key_exists ? $value : NULL;
-      }
-    }
+    return NestedArray::getData($this->overriddenData, $key);
   }
 
   /**
@@ -218,16 +206,7 @@ class Config {
   public function set($key, $value) {
     // Type-cast value into a string.
     $value = $this->castValue($value);
-
-    // The dot/period is a reserved character; it may appear between keys, but
-    // not within keys.
-    $parts = explode('.', $key);
-    if (count($parts) == 1) {
-      $this->data[$key] = $value;
-    }
-    else {
-      NestedArray::setValue($this->data, $parts, $value);
-    }
+    NestedArray::setData($this->data, $key, $value);
     $this->resetOverriddenData();
     return $this;
   }
@@ -249,26 +228,7 @@ class Config {
    *   The value cast to a string or array.
    */
   public function castValue($value) {
-    if (is_scalar($value)) {
-      // Handle special case of FALSE, which should be '0' instead of ''.
-      if ($value === FALSE) {
-        $value = '0';
-      }
-      else {
-        $value = (string) $value;
-      }
-    }
-    else {
-      // Any non-scalar value must be an array.
-      if (!is_array($value)) {
-        $value = (array) $value;
-      }
-      // Recurse into any nested keys.
-      foreach ($value as $key => $nested_value) {
-        $value[$key] = $this->castValue($nested_value);
-      }
-    }
-    return $value;
+    return NestedArray::castToStrings($value);
   }
 
   /**
@@ -278,13 +238,7 @@ class Config {
    *   Name of the key whose value should be unset.
    */
   public function clear($key) {
-    $parts = explode('.', $key);
-    if (count($parts) == 1) {
-      unset($this->data[$key]);
-    }
-    else {
-      NestedArray::unsetValue($this->data, $parts);
-    }
+    NestedArray::unsetData($this->data, $key);
     $this->resetOverriddenData();
     return $this;
   }
@@ -310,7 +264,7 @@ class Config {
    * Saves the configuration object.
    */
   public function save() {
-    $this->sortByKey($this->data);
+    NestedArray::sortByKey($this->data);
     $this->storage->write($this->name, $this->data);
     $this->isNew = FALSE;
     $this->notify('save');
@@ -331,26 +285,6 @@ class Config {
   }
 
   /**
-   * Sorts all keys in configuration data.
-   *
-   * Ensures that re-inserted keys appear in the same location as before, in
-   * order to ensure an identical order regardless of storage controller.
-   * A consistent order is important for any storage that allows any kind of
-   * diff operation.
-   *
-   * @param array $data
-   *   An associative array to sort recursively by key name.
-   */
-  public function sortByKey(array &$data) {
-    ksort($data);
-    foreach ($data as &$value) {
-      if (is_array($value)) {
-        $this->sortByKey($value);
-      }
-    }
-  }
-
-  /**
    * Deletes the configuration object.
    */
   public function delete() {
diff --git a/core/lib/Drupal/Core/Config/ConfigMetadata.php b/core/lib/Drupal/Core/Config/ConfigMetadata.php
new file mode 100644
index 0000000..68d9510
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigMetadata.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\ConfigMetadata.
+ *
+ * Metadata lives in a modules 'meta' directory, next to the 'config' directory,
+ * which contains the actual configuration. For each entry in an actual
+ * configuration file, the corresponding metadata file contains an entry with
+ * the following sub-keys:
+ * - label: The human-readable name for this configuration item.
+ * - type: The data type of this configuration item. Valid types include string,
+ *   boolean, integer, and other types defined by hook_data_type_info() ...
+ *
+ * The name of the configuration object may contain the placeholder '__' as the
+ * last component, which denotes generic metadata for all objects of this
+ * type. For the 'large' image style, for example, both "image.style.__" and
+ * "image.style.large" would be valid metadata files. In case both of these
+ * files exist, we load the generic metadata (in this example from
+ * "image.style.__") first and add the specific metadata (in this example from
+ * "image.style.large") on top of it.
+ */
+
+namespace Drupal\Core\Config;
+
+use Drupal\Core\Utility\CacheArray;
+use Drupal\Core\Config\FileStorage;
+use Drupal\Component\Utility\NestedArray;
+use Symfony\Component\Yaml\Parser;
+
+/**
+ * Defines the default configuration metadata object.
+ */
+class ConfigMetadata extends CacheArray {
+
+  /**
+   * Filesystem marker for base metadata name.
+   */
+  const BASE_MARK = '__';
+
+  /**
+   * Constructs a ConfigMetadata cache object.
+   */
+  public function __construct() {
+    parent::__construct('config:metadata', 'cache');
+  }
+
+  /**
+   * Overrides DrupalCacheArray::resolveCacheMiss().
+   */
+  protected function resolveCacheMiss($offset) {
+    $metadata = array();
+    // Get base metadata if available.
+    if ($basename = $this->getBaseName($offset)) {
+      $metadata = $this->offsetGet($basename);
+    }
+    // Merge current metadata on top of it.
+    if ($meta = $this->readMetadata($offset)) {
+      $metadata = NestedArray::mergeDeep($metadata, $meta);
+    }
+    $this->storage[$offset] = $metadata;
+    return $metadata;
+  }
+
+  /**
+   * Get parent metadata name.
+   */
+  protected static function getBaseName($name) {
+    $parts = explode('.', $name);
+    $last = array_pop($parts);
+    // If this is not the generic metadata (where the last component of the
+    // name is a '+'), try to load that first.
+    if ($last != self::BASE_MARK) {
+      return implode('.', array_merge($parts, array(self::BASE_MARK)));
+    }
+  }
+
+  /**
+   * Read metadata from file system.
+   *
+   * @return array
+   *   Metadata array if found or empty array if not.
+   */
+  protected function readMetadata($name) {
+    $module = strtok($name, '.');
+    // We are looking for a file in $module/meta/$name.yml
+    $directory = drupal_get_path('module', $module) . '/meta';
+    $filepath = $directory  . '/' . $name . '.yml';
+    if (file_exists($filepath)) {
+      // We use FileStorage as a convenience though we could add our
+      // own reader and parser here.
+      try {
+        $storage = new FileStorage($directory);
+        return $storage->read($name);
+      }
+      catch (Drupal\Core\Config\FileStorageReadException $e) {
+        // Either the file does not exist or we cannot decode it.
+        // Do nothing. In the worst case, the value will be an empty array.
+        // @todo In that worst case, we should probably at least watchdog() or
+        //   something.
+      }
+    }
+    return array();
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/ConfigWrapper.php b/core/lib/Drupal/Core/Config/ConfigWrapper.php
new file mode 100644
index 0000000..1d2526e
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ConfigWrapper.php
@@ -0,0 +1,356 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\ConfigWrapper.
+ */
+
+namespace Drupal\Core\Config;
+
+use Drupal\Core\Config\Config;
+use Drupal\Core\Config\ConfigMetadata;
+use Drupal\Core\TypedData\StructureInterface;
+use Drupal\Core\TypedData\Type\Variant;
+use Drupal\Component\Utility\NestedArray;
+
+/**
+ * Defines the default configuration metadata object.
+ */
+class ConfigWrapper {
+
+  /**
+   * The name of the configuration object.
+   *
+   * @var string
+   */
+  protected $name;
+
+  /**
+   * The medatada of the configuration object.
+   *
+   * @var array
+   */
+  protected $metadata;
+
+  /**
+   * The configuration object data.
+   *
+   * @var array
+   */
+  protected $configData;
+
+  /**
+   * The typed data of the configuration object as nested array.
+   *
+   * @var array
+   */
+  protected $typedData;
+
+  /**
+   * Constructs a configuration metadata object.
+   *
+   * @param string $name
+   *   The name of the configuration object being constructed.
+   */
+  public function __construct($name, $metadata = NULL, $configData = NULL) {
+    $this->name = $name;
+    $this->metadata = $metadata;
+    $this->configData = $configData;
+  }
+
+
+  /**
+   * Gets medata array from this config metadata.
+   *
+   * An array of metadata contains the 'label' and 'type' keys as explained above.
+   * If $key is omitted, the full array is returned, where the array keys are the
+   * metadata keys and the values are the metadata arrays (see above).
+   *
+   * @param $key
+   *   Optional string that maps to a key within the configuration metadata.
+   * @return
+   *   The metadata property that was requested or the full metadata array.
+   */
+  public function getMetadata($key = '') {
+    if (!isset($this->metadata)) {
+      $this->metadata = config_metadata($this->name);
+    }
+    if ($key) {
+      return isset($this->metadata[$key]) ? $this->metadata[$key] : array();
+    }
+    else {
+      return $this->metadata;
+    }
+  }
+
+  /**
+   * Gets raw configuration data.
+   *
+   * @return array
+   *   Reference to array of configuration data.
+   */
+  public function &getConfigData() {
+    if (!isset($this->configData)) {
+      $this->configData = config($this->name)->get();
+    }
+    return $this->configData;
+  }
+
+  /**
+   * Get typed data as nested array.
+   *
+   * @return
+   *   Reference to nested array with Drupal\Core\TypedData\WrapperInterface elements.
+   */
+  public function &getTypedData() {
+    if (!isset($this->typedData)) {
+      $this->typedData = $this->buildTypedData($this->getConfigData());
+    }
+    return $this->typedData;
+  }
+
+  /**
+   * Builds properties using configuration data and metadata.
+   *
+   * The result will be a nested array merging the full configuration data and
+   * the metadata. The array keys will be the property names
+   * and the array values will be data properties.
+   *
+   * Example:
+   *
+   * - Data: module/system/config/system.site.yml
+   *
+   *   name: Drupal
+   *     mail: ''
+   *     slogan: ''
+   *   page:
+   *     403: ''
+   *     404: ''
+   *     front: user
+   *
+   * - Metadata: module/system/meta/system.site.yml
+   *
+   *   name:
+   *     label: 'Site name'
+   *     type: 'string'
+   *   mail:
+   *     label: 'Site mail'
+   *     type: 'email'
+   *   slogan:
+   *     label: 'Site slogan'
+   *     type: 'string'
+   *   page:
+   *     label: 'Error pages'
+   *     type: config_subkeys
+   *   page.403:
+   *     label: 'Default 403 (access denied) page'
+   *     type: 'path'
+   *   page.404:
+   *     label: 'Default 404 (not found) page'
+   *     type: 'path'
+   *   page.front:
+   *     label: 'Default front page'
+   *     type: 'path'
+   *
+   * @param $data
+   *   Array of configuration data.
+   * @param $name
+   *   Base name to use for all elements.
+   */
+  protected function buildTypedData($data, $name = '') {
+    $build = array();
+    foreach ($data as $key => $value) {
+      $key_name = $name ? $name . '.' . $key : $key;
+      $meta = $this->getMetadata($key_name);
+      $build[$key] = $this->buildElement($key_name, $value, $meta);
+    }
+    return $build;
+  }
+
+  /**
+   * Build configuration element with data and metadata.
+   *
+   * @param $name
+   *   Element key
+   * @param $data
+   *   Base name for this element.
+   * @param $meta
+   *   Metadata for this element.
+   *
+   * @result array
+   *   Built metadata array with one or more elements.
+   */
+  protected function buildElement($name, $data, $meta) {
+    if (!isset($meta['type'])) {
+      $meta['type'] = 'variant';
+    }
+    // $build[$key] = $meta;
+    // Build element depending on type.
+    switch ($meta['type']) {
+      case 'config_nested':
+        // This is an array of nested configuration elements.
+        return $this->buildNested($name, $data, $meta);
+
+      case 'config_subkeys':
+        // Array with multiple nested properties.
+        return $this->buildSubkeys($name, $data, $meta);
+
+      default:
+        // This is an end property. The metadata will be the property definition.
+        return $this->buildProperty($name, $data, $meta);
+    }
+  }
+
+  /**
+   * Build nested configuration array.
+   *
+   * Example metadata from image.style.+.yml
+   *
+   * effects:
+   *   label: 'Style effects'
+   *   type: 'nested_config'
+   *   config_name: 'image.style.effects.*'
+   *
+   * Example data from image.style.large.yml
+   *
+   * effects:
+   *   ddd73aa7-4bd6-4c85-b600-bdf2b1628d1d:
+   *     name: image.style.effects.scale
+   *     data:
+   *       width: '480'
+   *       height: '480'
+   *       upscale: '1'
+   *     weight: '0'
+   *     ieid: ddd73aa7-4bd6-4c85-b600-bdf2b1628d1d
+   */
+  protected function buildNested($name, $data, $meta) {
+    $build = array();
+    $base_meta = isset($meta['config_name']) ? config_metadata($meta['config_name']) : array();
+    foreach ($data as $key => $value) {
+      $key_name = $name . '.' . $key;
+      // For nested elements, the parent metadata file declares the child element
+      // using the 'config_name' key. Actual configuration files directly specify
+      // the nested configuration in one file and denote the child element with
+      // the 'name' key.
+      $nested_meta = $this->getMetadata($key_name);
+      if (!$nested_meta) {
+        $nested_meta = $base_meta;
+        if (isset($value['name'])) {
+          $nested_meta = NestedArray::mergeDeep($nested_meta, config_metadata($value['name']));
+        }
+        // Store nested element metadata in case we need to rebuild.
+        $this->metadata[$key_name] = $nested_meta;
+      }
+      // Build this element with metadata taken from a different object.
+      $nested_config = new ConfigWrapper($key_name, $nested_meta, $value);
+      $build[$key] = $nested_config->getTypedData();
+    }
+    return $build;
+  }
+
+  /**
+   * Build array of configuration data with subkeys.
+   *
+   * Example metadata from image.style.effects.+.yml + image.style.effects.scale.yml
+   *
+   * data:
+   *   label: 'Data'
+   *   type: 'config_subkeys'
+   * data.width:
+   *   label: 'Width'
+   *   type: 'integer'
+   * data.height:
+   *   label: 'Height'
+   *   type: 'integer'
+   * data.upscale:
+   *  label: 'Upscale'
+   *  type: 'boolean'
+   *
+   * Example data from image.style.large.yml (effects/../data)
+   *
+   *    width: '480'
+   *    height: '480'
+   *    upscale: '1'
+   *
+   * @param $data
+   *   Array of configuration data.
+   * @param $meta
+   *
+   * @param $key
+   *   Key to prepend to the data to match it with the metadata.
+   */
+  protected function buildSubkeys($name, $data, $meta) {
+    // Prefix all data with given key and build as usual.
+    $build = array();
+    foreach ($data as $key => $value) {
+      $key_name = $name . '.' . $key;
+      $key_meta = $this->getMetadata($key_name);
+      $build[$key] = $this->buildElement($key_name, $value, $key_meta);
+    }
+    return $build;
+  }
+
+  /**
+   * Builds property as typed data.
+   *
+   * @see drupal_wrap_data();
+   *
+   * @return Drupal\Core\TypedData\WrapperInterface
+   *   Property as typed data.
+   */
+  protected function buildProperty($name, $value = NULL, array $definition = array()) {
+    $type_info = drupal_get_data_type_info();
+    $context = array(
+        'name' => $name,
+        'parent' => $this,
+    );
+    // Allow per-data definition overrides of the used classes.
+    if (isset($definition['type']) && isset($type_info[$definition['type']])) {
+      $full_definition = $definition + $type_info[$definition['type']];
+    }
+    else {
+      // We use a variant data type for properties that don't have a known type.
+      $full_definition = $definition + array('type' => 'variant', 'class' => 'Drupal\Core\TypedData\Type\Variant');
+    }
+    $class = empty($full_definition['list']) ? $full_definition['class'] : $full_definition['list class'];
+    return new $class($full_definition, $value, $context);
+  }
+
+  /**
+   * Gets typed data from this configuration object.
+   *
+   * @param string $key
+   *
+   * @return
+   *   Object or array of WrapperInterface objects.
+   */
+  public function get($key) {
+    return NestedArray::getData($this->getTypedData(), $key);
+  }
+
+  /**
+   * Sets typed data in this config object.
+   *
+   * @param string $key
+   *   The name of the property to set; e.g., 'title' or 'name'.
+   * @param $value
+   *   Object or array of WrapperInterface objects to set.
+   */
+  public function set($key, $value) {
+    NestedArray::setData($this->getTypedData(), $key, $value);
+    // Update the underlying configuration data.
+    $value = NestedArray::castToStrings($value);
+    NestedArray::setData($this->getConfigData(), $key, $value);
+    return $this;
+  }
+
+  /**
+   * Gets all typed data properties as plain array.
+   *
+   * @return array
+   *   Plain array of WrapperInterface objects indexed by full name (keys with dot notation).
+   */
+  public function toList() {
+    return NestedArray::toList($this->getTypedData());
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
new file mode 100644
index 0000000..3c42f7a
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\AccessibleInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for checking access.
+ */
+interface AccessibleInterface {
+
+  /**
+   * Check data value access.
+   *
+   * @param \Drupal\user\User $account
+   *   (optional) The user account to check access for. Defaults to the current
+   *   user.
+   *
+   * @return bool
+   *   Whether the given user has access.
+   */
+  public function access(\Drupal\user\User $account = NULL);
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/ListInterface.php b/core/lib/Drupal/Core/TypedData/ListInterface.php
new file mode 100644
index 0000000..4803330
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/ListInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\ListInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+use ArrayAccess;
+use IteratorAggregate;
+use Countable;
+
+/**
+ * Interface for a list of typed data.
+ */
+interface ListInterface extends ArrayAccess, IteratorAggregate , Countable {
+
+  /**
+   * Determines whether the list contains any non-empty items.
+   *
+   * @return boolean
+   *   TRUE if the list is empty, FALSE otherwise.
+   */
+  public function isEmpty();
+}
diff --git a/core/lib/Drupal/Core/TypedData/MissingContextException.php b/core/lib/Drupal/Core/TypedData/MissingContextException.php
new file mode 100644
index 0000000..91fcbd7
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/MissingContextException.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\MissingContextException.
+ */
+
+namespace Drupal\Core\TypedData;
+use Exception;
+
+/**
+ * Exception thrown when data wrappers miss contextual information.
+ */
+class MissingContextException extends Exception { }
diff --git a/core/lib/Drupal/Core/TypedData/Primitive.php b/core/lib/Drupal/Core/TypedData/Primitive.php
new file mode 100644
index 0000000..461d5fb
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Primitive.php
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Primitive.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Class that holds constants for all primitive data types.
+ */
+final class Primitive {
+
+  /**
+   * The BOOLEAN primitive data type.
+   */
+  const BOOLEAN = 1;
+
+  /**
+   * The STRING primitive data type.
+   */
+  const STRING = 2;
+
+  /**
+   * The INTEGER primitive data type.
+   */
+  const INTEGER = 3;
+
+  /**
+   * The DECIMAL primitive data type.
+   */
+  const DECIMAL = 4;
+
+  /**
+   * The DATE primitive data type.
+   */
+  const DATE = 5;
+
+  /**
+   * The DURATION primitive data type.
+   */
+  const DURATION = 6;
+
+  /**
+   * The URI primitive data type.
+   */
+  const URI = 7;
+
+  /**
+   * The BINARY primitive data type.
+   */
+  const BINARY = 8;
+
+}
diff --git a/core/lib/Drupal/Core/TypedData/ReadOnlyException.php b/core/lib/Drupal/Core/TypedData/ReadOnlyException.php
new file mode 100644
index 0000000..d116f22
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/ReadOnlyException.php
@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\ReadOnlyException.
+ */
+
+namespace Drupal\Core\TypedData;
+use Exception;
+
+/**
+ * Exception thrown when trying to write or set ready-only data.
+ */
+class ReadOnlyException extends Exception { }
diff --git a/core/lib/Drupal/Core/TypedData/StructureInterface.php b/core/lib/Drupal/Core/TypedData/StructureInterface.php
new file mode 100644
index 0000000..1aba93f
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/StructureInterface.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\StructureInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+use IteratorAggregate;
+
+/**
+ * Interface for data structures that contain properties.
+ *
+ * This is implemented by entities as well as by EntityPropertyItem classes of
+ * the entity.module.
+ */
+interface StructureInterface extends IteratorAggregate  {
+
+  /**
+   * Gets a property.
+   *
+   * @param $property_name
+   *   The name of the property to get; e.g., 'title' or 'name'.
+   *
+   * @throws \InvalidArgumentException
+   *   If an invalid property name is given.
+   *
+   * @return \Drupal\Core\TypedData\WrapperInterface
+   *   The property object.
+   */
+  public function get($property_name);
+
+  /**
+   * Sets a property.
+   *
+   * @param $property_name
+   *   The name of the property to set; e.g., 'title' or 'name'.
+   * @param $value
+   *   The value to set, or NULL to unset the property.
+   *
+   * @throws \InvalidArgumentException
+   *   If an invalid property name is given.
+   *
+   * @return \Drupal\Core\TypedData\WrapperInterface
+   *   The property object.
+   */
+  public function set($property_name, $value);
+
+  /**
+   * Gets an array of properties.
+   *
+   * @param bool $include_computed
+   *   If set to TRUE, computed properties are included. Defaults to FALSE.
+   *
+   * @return array
+   *   An array of property objects implementing the WrapperInterface, keyed
+   *   by property name.
+   */
+  public function getProperties($include_computed = FALSE);
+
+  /**
+   * Sets an array of properties.
+   *
+   * @param array
+   *   The array of properties to set. The array has to consist of property
+   *   values or property objects implementing the WrapperInterface and must
+   *   be keyed by property name.
+   *
+   * @throws \InvalidArgumentException
+   *   If an not existing property is passed.
+   * @throws \Drupal\Core\TypedData\ReadOnlyException
+   *   If a read-only property is set.
+   */
+  public function setProperties($properties);
+
+  /**
+   * Gets the definition of a contained property.
+   *
+   * @param string $name
+   *   The name of property.
+   *
+   * @return array|FALSE
+   *   The definition of the property or FALSE if the property does not exist.
+   */
+  public function getPropertyDefinition($name);
+
+  /**
+   * Gets an array property definitions of contained properties.
+   *
+   * @param array $definition
+   *   The definition of the container's property, e.g. the definition of an
+   *   entity reference property.
+   *
+   * @return array
+   *   An array of property definitions of contained properties, keyed by
+   *   property name.
+   */
+  public function getPropertyDefinitions();
+
+  /**
+   * Gets the plain values of the contained properties.
+   *
+   * @return array
+   *   An array keyed by property name containing the plain property values.
+   */
+  public function toArray();
+
+  /**
+   * Determines whether the data structure is empty.
+   *
+   * @return boolean
+   *   TRUE if the data structure is empty, FALSE otherwise.
+   */
+  public function isEmpty();
+}
diff --git a/core/lib/Drupal/Core/TypedData/StructureTranslatableInterface.php b/core/lib/Drupal/Core/TypedData/StructureTranslatableInterface.php
new file mode 100644
index 0000000..74f5566
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/StructureTranslatableInterface.php
@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\StructureTranslatableInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+
+/**
+ * Interface for translatable data structures.
+ */
+interface StructureTranslatableInterface extends StructureInterface {
+
+  /**
+   * Returns the default language.
+   *
+   * @return
+   *   The language object.
+   */
+  public function language();
+
+  /**
+   * Returns the languages the data is translated to.
+   *
+   * @param bool $include_default
+   *   Whether the default language should be included.
+   *
+   * @return
+   *   An array of language objects, keyed by language codes.
+   */
+  public function getTranslationLanguages($include_default = TRUE);
+
+  /**
+   * Gets a translation of contained properties.
+   *
+   * @param $langcode
+   *   The language code of the translation to get or LANGUAGE_DEFAULT to get
+   *   the data in default language.
+   *
+   * @return \Drupal\Core\TypedData\StructureInterface
+   *   A data structure containing the translated properties.
+   */
+  public function getTranslation($langcode);
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Binary.php b/core/lib/Drupal/Core/TypedData/Type/Binary.php
new file mode 100644
index 0000000..12e3962
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Binary.php
@@ -0,0 +1,81 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Binary.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+use InvalidArgumentException;
+
+/**
+ * The binary data type.
+ *
+ * The plain value of binary data is a PHP resource, see
+ * http://php.net/manual/en/language.types.resource.php. For setting the value
+ * a PHP resource or a (absolute) stream resource URI may be passed.
+ */
+class Binary extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The resource URI.
+   *
+   * @var string
+   */
+  protected $uri;
+
+  /**
+   * A generic resource handle.
+   *
+   * @var resource
+   */
+  public $handle = NULL;
+
+  /**
+   * Implements WrapperInterface::getValue().
+   */
+  public function getValue() {
+    if (!isset($this->handle) && isset($this->uri)) {
+      $this->handle = fopen($this->uri, 'rb');
+    }
+    return $this->handle;
+  }
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    if (!isset($value)) {
+      $this->handle = NULL;
+      $this->uri = NULL;
+    }
+    elseif (is_resource($value)) {
+      $this->handle = $value;
+    }
+    elseif (is_string($value)) {
+      $this->uri = $value;
+    }
+    else {
+      throw new InvalidArgumentException("Invalid value for binary data given.");
+    }
+  }
+
+  /**
+   * Implements WrapperInterface::getString().
+   */
+  public function getString() {
+    $contents = '';
+    while (!feof($this->getValue())) {
+      $contents .= fread($this->handle, 8192);
+    }
+    return $contents;
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Boolean.php b/core/lib/Drupal/Core/TypedData/Type/Boolean.php
new file mode 100644
index 0000000..de67e06
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Boolean.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Boolean.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The boolean data type.
+ *
+ * The plain value of a boolean is a regular PHP boolean. For setting the value
+ * any PHP variable that casts to a boolean may be passed.
+ */
+class Boolean extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var boolean
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    $this->value = isset($value) ? (bool) $value : $value;
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Date.php b/core/lib/Drupal/Core/TypedData/Type/Date.php
new file mode 100644
index 0000000..a60c20d
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Date.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Date.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+use DateTime;
+use InvalidArgumentException;
+
+/**
+ * The date data type.
+ *
+ * The plain value of a date is an instance of the DateTime class. For setting
+ * the value an instance of the DateTime class, any string supported by
+ * DateTime::__construct(), or a timestamp as integer may be passed.
+ */
+class Date extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var DateTime
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::getValue().
+   */
+  public function getValue() {
+    return $this->value;
+  }
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    if ($value instanceof DateTime || !isset($value)) {
+      $this->value = $value;
+    }
+    elseif (is_numeric($value)) {
+      // Value is a timestamp.
+      $this->value = new DateTime('@' . $value);
+    }
+    elseif (is_string($value)) {
+      $this->value = new DateTime($value);
+    }
+    else {
+      throw new InvalidArgumentException("Invalid date format given.");
+    }
+  }
+
+  /**
+   * Implements WrapperInterface::getString().
+   */
+  public function getString() {
+    return (string) $this->getValue()->format(DateTime::ISO8601);
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Decimal.php b/core/lib/Drupal/Core/TypedData/Type/Decimal.php
new file mode 100644
index 0000000..3bede7e
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Decimal.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Decimal.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The decimal data type.
+ *
+ * The plain value of a decimal is a regular PHP float. For setting the value
+ * any PHP variable that casts to a float may be passed.
+ */
+class Decimal extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var float
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    $this->value = isset($value) ? (float) $value : $value;
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Duration.php b/core/lib/Drupal/Core/TypedData/Type/Duration.php
new file mode 100644
index 0000000..5dc8fc9
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Duration.php
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Duration.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+use DateInterval;
+use InvalidArgumentException;
+
+/**
+ * The duration data type.
+ *
+ * The plain value of a duration is an instance of the DateInterval class. For
+ * setting the value an instance of the DateInterval class, a ISO8601 string as
+ * supported by DateInterval::__construct, or an integer in seconds may be
+ * passed.
+ */
+class Duration extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var \DateInterval
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    if ($value instanceof DateInterval || !isset($value)) {
+      $this->value = $value;
+    }
+    elseif (is_numeric($value)) {
+      // Value is a time span in seconds.
+      $this->value = new DateInterval('PT' . $value . 'S');
+    }
+    elseif (is_string($value)) {
+      // @todo: Add support for negative intervals on top of the DateInterval
+      // constructor.
+      $this->value = new DateInterval($value);
+    }
+    else {
+      throw new InvalidArgumentException("Invalid duration format given.");
+    }
+  }
+
+  /**
+   * Implements WrapperInterface::getString().
+   */
+  public function getString() {
+    // Generate an ISO 8601 formatted string as supported by
+    // DateInterval::__construct() and setValue().
+    return (string) $this->getValue()->format('%rP%yY%mM%dDT%hH%mM%sS');
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Integer.php b/core/lib/Drupal/Core/TypedData/Type/Integer.php
new file mode 100644
index 0000000..1d6bf3f
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Integer.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Integer.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The integer data type.
+ *
+ * The plain value of an integer is a regular PHP integer. For setting the value
+ * any PHP variable that casts to an integer may be passed.
+ */
+class Integer extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var integer
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    $this->value = isset($value) ? (int) $value : $value;
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Language.php b/core/lib/Drupal/Core/TypedData/Type/Language.php
new file mode 100644
index 0000000..068a32e
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Language.php
@@ -0,0 +1,93 @@
+<?php
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Language.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+use InvalidArgumentException;
+
+/**
+ * Defines the 'language' data type, e.g. the computed 'language' property of language items.
+ *
+ * The plain value of a language is the language object, i.e. an instance of
+ * Drupal\Core\Language\Language. For setting the value the language object or
+ * the language code as string may be passed.
+ *
+ * Supported settings (below the definition's 'settings' key) are:
+ *  - langcode source: If used as computed property, the langcode property used
+ *    to load the language object.
+ */
+class Language extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data wrapper holding the langcode value.
+   *
+   * @var \Drupal\Core\TypedData\WrapperInterface
+   */
+  protected $langcode;
+
+  /**
+   * Implements WrapperInterface::__construct().
+   */
+  public function __construct(array $definition, $value = NULL, array $context = array()) {
+    $this->definition = $definition;
+
+    if (isset($context['parent']) && !empty($this->definition['settings']['langcode source'])) {
+      $this->langcode = $context['parent']->get($this->definition['settings']['langcode source']);
+    }
+    else {
+      // No context given, so just initialize an langcode property for storing
+      // the code.
+      $this->langcode = drupal_wrap_data(array('type' => 'string'));
+    }
+
+    if (isset($value)) {
+      $this->setValue($value);
+    }
+  }
+
+  /**
+   * Implements WrapperInterface::getValue().
+   */
+  public function getValue() {
+    $langcode = $this->langcode->getValue();
+    return $langcode ? language_load($langcode) : NULL;
+  }
+
+  /**
+   * Implements WrapperInterface::setValue().
+   *
+   * Both the langcode and the language object may be passed as value.
+   */
+  public function setValue($value) {
+    if (!isset($value)) {
+      $this->langcode->setValue(NULL);
+    }
+    elseif (is_scalar($value)) {
+      $this->langcode->setValue($value);
+    }
+    elseif (is_object($value)) {
+      $this->langcode->setValue($value->langcode);
+    }
+    else {
+      throw new InvalidArgumentException('Value is no valid langcode or language object.');
+    }
+  }
+
+  /**
+   * Implements WrapperInterface::getString().
+   */
+  public function getString() {
+    $language = $this->getValue();
+    return $language ? $language->name : '';
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/String.php b/core/lib/Drupal/Core/TypedData/Type/String.php
new file mode 100644
index 0000000..f87e111
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/String.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\String.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The string data type.
+ *
+ * The plain value of a string is a regular PHP string. For setting the value
+ * any PHP variable that casts to a string may be passed.
+ */
+class String extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var string
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Uri.php b/core/lib/Drupal/Core/TypedData/Type/Uri.php
new file mode 100644
index 0000000..9b933ea
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Uri.php
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Uri.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The URI data type.
+ *
+ * The plain value of a URI is an absolute URI represented as PHP string.
+ */
+class Uri extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var string
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    $this->value = isset($value) ? (string) $value : $value;
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/Variant.php b/core/lib/Drupal/Core/TypedData/Type/Variant.php
new file mode 100644
index 0000000..ceee7f4
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/Variant.php
@@ -0,0 +1,39 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\Variant.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The variant data type.
+ *
+ * The plain value of a string is a regular PHP string. For setting the value
+ * any PHP variable that casts to a string may be passed.
+ */
+class Variant extends WrapperBase implements WrapperInterface {
+
+  /**
+   * The data value.
+   *
+   * @var string
+   */
+  protected $value;
+
+  /**
+   * Implements WrapperInterface::setValue().
+   */
+  public function setValue($value) {
+    $this->value = isset($value) ? (string) $value : $value;
+  }
+
+  /**
+   * Implements WrapperInterface::validate().
+   */
+  public function validate() {
+    // TODO: Implement validate() method.
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/Type/WrapperBase.php b/core/lib/Drupal/Core/TypedData/Type/WrapperBase.php
new file mode 100644
index 0000000..6411cb6
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/Type/WrapperBase.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\Type\WrapperBase.
+ */
+
+namespace Drupal\Core\TypedData\Type;
+use Drupal\Core\TypedData\WrapperInterface;
+
+/**
+ * The abstract base class for data types.
+ *
+ * Classes deriving from this base class have to declare $value
+ * or override getValue() or setValue().
+ */
+abstract class WrapperBase implements WrapperInterface {
+
+  /**
+   * The data definition.
+   *
+   * @var array
+   */
+  protected $definition;
+
+  /**
+   * Implements WrapperInterface::__construct().
+   *
+   * @param array $definition
+   *
+   * @param mixed $value;
+   *
+   * @param array $context;
+   */
+  public function __construct(array $definition, $value = NULL, array $context = array()) {
+    $this->definition = $definition;
+    if (isset($value)) {
+      $this->setValue($value);
+    }
+  }
+
+  /**
+   * Implements WrapperInterface::getType().
+   *
+   * @return string
+   */
+  public function getType() {
+    return $this->definition['type'];
+  }
+
+  /**
+   * Implements WrapperInterface::getDefinition().
+   *
+   * @return array
+   */
+  public function getDefinition() {
+    return $this->definition;
+  }
+
+  /**
+   * Implements WrapperInterface::getValue().
+   *
+   * @return mixed
+   */
+  public function getValue() {
+    return $this->value;
+  }
+
+  /**
+   * Implements WrapperInterface::setValue().
+   *
+   * @param mixed $value
+   */
+  public function setValue($value) {
+    $this->value = $value;
+  }
+
+  /**
+   * Implements WrapperInterface::getString().
+   *
+   * @return string
+   */
+  public function getString() {
+    return (string) $this->getValue();
+  }
+}
diff --git a/core/lib/Drupal/Core/TypedData/WrapperInterface.php b/core/lib/Drupal/Core/TypedData/WrapperInterface.php
new file mode 100644
index 0000000..75acaf5
--- /dev/null
+++ b/core/lib/Drupal/Core/TypedData/WrapperInterface.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\TypedData\WrapperInterface.
+ */
+
+namespace Drupal\Core\TypedData;
+use Drupal\user;
+
+/**
+ * Interface for typed data wrappers.
+ */
+interface WrapperInterface {
+
+  /**
+   * Creates a wrapper object given its definition and value.
+   *
+   * @param array $definition
+   *   The data definition.
+   * @param mixed $value
+   *   (optional) The data value, or NULL if the it is not set. See
+   *   WrapperInterface::setValue() for details.
+   * @param array $context
+   *   (optional) An array describing the context of the data. It should be
+   *   passed if a data value is wrapped as part of a data structure. The
+   *   following keys are supported:
+   *   - name: The name of the data being wrapped.
+   *   - parent: The parent object containing the data. Must be an instance of
+   *     \Drupal\Core\TypedData\StructureInterface.
+   *
+   * @see drupal_wrap_data()
+   */
+  public function __construct(array $definition, $value = NULL, array $context = array());
+
+  /**
+   * Gets the data type.
+   *
+   * @return string
+   *   The data type of the wrapped data.
+   */
+  public function getType();
+
+  /**
+   * Gets the data definition.
+   *
+   * @return array
+   *   The data definition array.
+   */
+  public function getDefinition();
+
+  /**
+   * Gets the data value.
+   *
+   * @return mixed
+   */
+  public function getValue();
+
+  /**
+   * Sets the data value.
+   *
+   * @param mixed $value
+   *   The value to set in the format as documented for the data type or NULL to
+   *   unset the data value.
+   *
+   * @throws \Drupal\Core\TypedData\ReadOnlyException
+   *   If the data is read-only.
+   */
+  public function setValue($value);
+
+  /**
+   * Returns a string representation of the data.
+   *
+   * @return string
+   */
+  public function getString();
+
+  /**
+   * Validates the currently set data value.
+   */
+  public function validate();
+
+}
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigMetadataTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigMetadataTest.php
new file mode 100644
index 0000000..8a4366e
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigMetadataTest.php
@@ -0,0 +1,147 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config\Tests\ConfigMetadataTest.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\Core\Config\ConfigWrapper;
+use Drupal\Core\TypedData\WrapperInterface;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests Metadata for configuration objects.
+ */
+class ConfigMetadataTest extends WebTestBase {
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('image');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Metadata',
+      'description' => 'Tests Metadata for configuration objects.',
+      'group' => 'Configuration',
+    );
+  }
+
+  /**
+   * Tests the basic metadata retrieval layer.
+   */
+  function testBasicMetadata() {
+    // Simple case, straight metadata.
+    $metadata = config_metadata('system.maintenance');
+    $expected = array(
+      'enabled' => array(
+        'label' => 'Put site into maintenance mode',
+        'type' => 'boolean'
+       ),
+      'message' => array(
+        'label' =>  'Message to display when in maintenance mode',
+        'type' => 'string'
+      ),
+    );
+    $this->assertEqual($metadata, $expected, 'Retrieved the right metadata for system.maintenance');
+    // More complex case, fallback to parent name.
+    $metadata = config_metadata('image.style.large');
+    $expected = array(
+      'name' => array(
+        'label' => 'Machine name',
+        'type' => 'machine_name'
+      ),
+      'effects' => array(
+        'label' =>  'Style effects',
+        'type' => 'config_nested',
+        'config_name' => 'image.style.effects.*'
+      )
+    );
+    $this->assertEqual($metadata, $expected, 'Retrieved the right metadata for image.style.large');
+
+    // Most complex case, fallback to parent name with merging
+    $metadata = config_metadata('image.style.effects.scale');
+    $expected = array(
+      'name' => array(
+        'label' => 'Style name'
+      ),
+      'data' => array(
+        'label' => 'Data',
+        'type' => 'config_subkeys',
+      ),
+      'weight' => array(
+        'label' => 'Weight',
+        'type' => 'integer'
+      ),
+      'ieid' => array(
+        'label' =>  'IEID',
+        'type' => 'ieid',
+      ),
+      'data.width' => array(
+        'label' => 'Width',
+        'type' => 'integer'
+      ),
+      'data.height' => array(
+        'label' =>  'Height',
+        'type' => 'integer',
+      ),
+      'data.upscale' => array(
+        'label' =>  'Upscale',
+        'type' => 'boolean',
+      )
+    );
+    $this->assertEqual($metadata, $expected, 'Retrieved the right metadata for image.style.effects.scale');
+
+  }
+
+  /**
+   * Tests metadata applied to configuration objects.
+   */
+  function testConfigMetadata() {
+    // Try some simple properties.
+    $meta = new ConfigWrapper('system.site');
+    $property = $meta->get('name');
+    $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Type\String'), 'Got the right wrapper fo the site name property.');
+    $this->assertEqual($property->getType(), 'string', 'Got the right string type for site name data.');
+    $this->assertEqual($property->getValue(), 'Drupal', 'Got the right string value for site name data.');
+
+    $property = $meta->get('page.front');
+    $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Type\Variant'), 'Got the right wrapper fo the page.front property.');
+    $this->assertEqual($property->getType(), 'path', 'Got the right string type for page.front data.');
+    $this->assertEqual($property->getValue(), 'user', 'Got the right value for page.front data.');
+
+    // Check nested array of properties.
+    $list = $meta->get('page');
+    $this->assertEqual(count($list), 3, 'Got a list with the right number of properties for site page data');
+    $this->assertTrue(isset($list['front']) && isset($list['403']) && isset($list['404']), 'Got a list with the right properties for site page data.');
+    $this->assertEqual($list['front']->getValue(), 'user', 'Got the right value for page.front data from the list.');
+
+    // Now let's try something more complex, with nested objects.
+    $wrapper = new ConfigWrapper('image.style.large');
+    $effects = $wrapper->get('effects');
+    debug($effects);
+    debug($wrapper);
+
+    $this->assertTrue(is_array($effects) && count($effects) == 1, 'Got an array with effects for image.style.large data');
+    $ieid = key($effects);
+    $effect = $wrapper->get('effects.' . $ieid);
+    debug($effect);
+
+    $this->assertTrue(is_array($effect) && is_array($effect['data']) && $effect['name']->getValue() == 'image.style.effects.scale', 'Got data for the image scale effect from metadata.');
+    $this->assertEqual($effect['data']['width']->getType(), 'integer', 'Got the right type for the scale effect width.');
+    $this->assertEqual($effect['data']['width']->getValue(), 480, 'Got the right value for the scale effect width.' );
+
+    // Finally update some object using a configuration wrapper.
+    $new_slogan = 'Site slogan for testing configuration metadata';
+    $wrapper = new ConfigWrapper('system.site');
+    $site_slogan = $wrapper->get('slogan');
+    $site_slogan->setValue($new_slogan);
+    $wrapper->set('slogan', $new_slogan);
+    $data = $wrapper->getConfigData();
+    $this->assertEqual($data['slogan'], $new_slogan, 'Successfully updated the contained configuration data');
+  }
+
+}
diff --git a/core/modules/image/config/image.style.large.yml b/core/modules/image/config/image.style.large.yml
index 3a1260d..f6ea671 100644
--- a/core/modules/image/config/image.style.large.yml
+++ b/core/modules/image/config/image.style.large.yml
@@ -1,7 +1,7 @@
 name: large
 effects:
   ddd73aa7-4bd6-4c85-b600-bdf2b1628d1d:
-    name: image_scale
+    name: image.style.effects.scale
     data:
       width: '480'
       height: '480'
diff --git a/core/modules/image/config/image.style.medium.yml b/core/modules/image/config/image.style.medium.yml
index 3f2b445..44e882a 100644
--- a/core/modules/image/config/image.style.medium.yml
+++ b/core/modules/image/config/image.style.medium.yml
@@ -1,7 +1,7 @@
 name: medium
 effects:
   bddf0d06-42f9-4c75-a700-a33cafa25ea0:
-    name: image_scale
+    name: image.style.effects.scale
     data:
       width: '220'
       height: '220'
diff --git a/core/modules/image/config/image.style.thumbnail.yml b/core/modules/image/config/image.style.thumbnail.yml
index 83e6730..de61ab5 100644
--- a/core/modules/image/config/image.style.thumbnail.yml
+++ b/core/modules/image/config/image.style.thumbnail.yml
@@ -1,7 +1,7 @@
 name: thumbnail
 effects:
   1cfec298-8620-4749-b100-ccb6c4500779:
-    name: image_scale
+    name: image.style.effects.scale
     data:
       width: '100'
       height: '100'
diff --git a/core/modules/image/image.effects.inc b/core/modules/image/image.effects.inc
index 35a6a74..d491796 100644
--- a/core/modules/image/image.effects.inc
+++ b/core/modules/image/image.effects.inc
@@ -10,7 +10,7 @@
  */
 function image_image_effect_info() {
   $effects = array(
-    'image_resize' => array(
+    'image.style.effects.resize' => array(
       'label' => t('Resize'),
       'help' => t('Resizing will make images an exact set of dimensions. This may cause images to be stretched or shrunk disproportionately.'),
       'effect callback' => 'image_resize_effect',
@@ -18,7 +18,7 @@ function image_image_effect_info() {
       'form callback' => 'image_resize_form',
       'summary theme' => 'image_resize_summary',
     ),
-    'image_scale' => array(
+    'image.style.effects.scale' => array(
       'label' => t('Scale'),
       'help' => t('Scaling will maintain the aspect-ratio of the original image. If only a single dimension is specified, the other dimension will be calculated.'),
       'effect callback' => 'image_scale_effect',
@@ -26,7 +26,7 @@ function image_image_effect_info() {
       'form callback' => 'image_scale_form',
       'summary theme' => 'image_scale_summary',
     ),
-    'image_scale_and_crop' => array(
+    'image.style.effects.scale_and_crop' => array(
       'label' => t('Scale and crop'),
       'help' => t('Scale and crop will maintain the aspect-ratio of the original image, then crop the larger dimension. This is most useful for creating perfectly square thumbnails without stretching the image.'),
       'effect callback' => 'image_scale_and_crop_effect',
@@ -34,7 +34,7 @@ function image_image_effect_info() {
       'form callback' => 'image_resize_form',
       'summary theme' => 'image_resize_summary',
     ),
-    'image_crop' => array(
+    'image.style.effects.crop' => array(
       'label' => t('Crop'),
       'help' => t('Cropping will remove portions of an image to make it the specified dimensions.'),
       'effect callback' => 'image_crop_effect',
@@ -42,13 +42,13 @@ function image_image_effect_info() {
       'form callback' => 'image_crop_form',
       'summary theme' => 'image_crop_summary',
     ),
-    'image_desaturate' => array(
+    'image.style.effects.desaturate' => array(
       'label' => t('Desaturate'),
       'help' => t('Desaturate converts an image to grayscale.'),
       'effect callback' => 'image_desaturate_effect',
       'dimensions passthrough' => TRUE,
     ),
-    'image_rotate' => array(
+    'image.style.effects.rotate' => array(
       'label' => t('Rotate'),
       'help' => t('Rotating an image may cause the dimensions of an image to increase to fit the diagonal.'),
       'effect callback' => 'image_rotate_effect',
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
index f2f8b0b..860cf33 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
@@ -67,28 +67,28 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
     $style_name = strtolower($this->randomName(10));
     $style_path = 'admin/config/media/image-styles/edit/' . $style_name;
     $effect_edits = array(
-      'image_resize' => array(
+      'image.style.effects.resize' => array(
         'data[width]' => 100,
         'data[height]' => 101,
       ),
-      'image_scale' => array(
+      'image.style.effects.scale' => array(
         'data[width]' => 110,
         'data[height]' => 111,
         'data[upscale]' => 1,
       ),
-      'image_scale_and_crop' => array(
+      'image.style.effects.scale_and_crop' => array(
         'data[width]' => 120,
         'data[height]' => 121,
       ),
-      'image_crop' => array(
+      'image.style.effects.crop' => array(
         'data[width]' => 130,
         'data[height]' => 131,
         'data[anchor]' => 'center-center',
       ),
-      'image_desaturate' => array(
+      'image.style.effects.desaturate' => array(
         // No options for desaturate.
       ),
-      'image_rotate' => array(
+      'image.style.effects.rotate' => array(
         'data[degrees]' => 5,
         'data[random]' => 1,
         'data[bgcolor]' => '#FFFF00',
@@ -266,7 +266,7 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
     // Add a scale effect.
     $this->drupalGet('admin/config/media/image-styles/add');
     $this->drupalPost(NULL, array('name' => 'test_style_effect_edit'), t('Create new style'));
-    $this->drupalPost(NULL, array('new' => 'image_scale_and_crop'), t('Add'));
+    $this->drupalPost(NULL, array('new' => 'image.style.effects.scale_and_crop'), t('Add'));
     $this->drupalPost(NULL, array('data[width]' => '300', 'data[height]' => '200'), t('Add effect'));
     $this->assertText(t('Scale and crop 300x200'));
 
@@ -281,13 +281,13 @@ class ImageAdminStylesTest extends ImageFieldTestBase {
     // Add another scale effect.
     $this->drupalGet('admin/config/media/image-styles/add');
     $this->drupalPost(NULL, array('name' => 'test_style_scale_edit_scale'), t('Create new style'));
-    $this->drupalPost(NULL, array('new' => 'image_scale'), t('Add'));
+    $this->drupalPost(NULL, array('new' => 'image.style.effects.scale'), t('Add'));
     $this->drupalPost(NULL, array('data[width]' => '12', 'data[height]' => '19'), t('Add effect'));
 
     // Edit the scale effect that was just added.
     $this->clickLink(t('edit'));
     $this->drupalPost(NULL, array('data[width]' => '24', 'data[height]' => '19'), t('Update effect'));
-    $this->drupalPost(NULL, array('new' => 'image_scale'), t('Add'));
+    $this->drupalPost(NULL, array('new' => 'image.style.effects.scale'), t('Add'));
 
     // Add another scale effect and make sure both exist.
     $this->drupalPost(NULL, array('data[width]' => '12', 'data[height]' => '19'), t('Add effect'));
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php
index 76110cf..c7e68b9 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php
@@ -58,7 +58,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Scale an image that is wider than it is high.
     $effect = array(
-      'name' => 'image_scale',
+      'name' => 'image.style.effects.scale',
       'data' => array(
         'width' => 120,
         'height' => 90,
@@ -80,7 +80,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Rotate 90 degrees anticlockwise.
     $effect = array(
-      'name' => 'image_rotate',
+      'name' => 'image.style.effects.rotate',
       'data' => array(
         'degrees' => -90,
         'random' => FALSE,
@@ -101,7 +101,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Scale an image that is higher than it is wide (rotated by previous effect).
     $effect = array(
-      'name' => 'image_scale',
+      'name' => 'image.style.effects.scale',
       'data' => array(
         'width' => 120,
         'height' => 90,
@@ -123,7 +123,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Test upscale disabled.
     $effect = array(
-      'name' => 'image_scale',
+      'name' => 'image.style.effects.scale',
       'data' => array(
         'width' => 400,
         'height' => 200,
@@ -145,7 +145,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Add a desaturate effect.
     $effect = array(
-      'name' => 'image_desaturate',
+      'name' => 'image.style.effects.desaturate',
       'data' => array(),
       'weight' => 4,
     );
@@ -163,7 +163,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Add a random rotate effect.
     $effect = array(
-      'name' => 'image_rotate',
+      'name' => 'image.style.effects.rotate',
       'data' => array(
         'degrees' => 180,
         'random' => TRUE,
@@ -182,7 +182,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Add a crop effect.
     $effect = array(
-      'name' => 'image_crop',
+      'name' => 'image.style.effects.crop',
       'data' => array(
         'width' => 30,
         'height' => 30,
@@ -204,7 +204,7 @@ class ImageDimensionsTest extends WebTestBase {
 
     // Rotate to a non-multiple of 90 degrees.
     $effect = array(
-      'name' => 'image_rotate',
+      'name' => 'image.style.effects.rotate',
       'data' => array(
         'degrees' => 57,
         'random' => FALSE,
diff --git a/core/modules/image/meta/image.style.__.yml b/core/modules/image/meta/image.style.__.yml
new file mode 100644
index 0000000..736effc
--- /dev/null
+++ b/core/modules/image/meta/image.style.__.yml
@@ -0,0 +1,7 @@
+name:
+  label: 'Machine name'
+  type: 'machine_name'
+effects:
+  label: 'Style effects'
+  type: 'config_nested'
+  config_name: 'image.style.effects.*'
diff --git a/core/modules/image/meta/image.style.effects.__.yml b/core/modules/image/meta/image.style.effects.__.yml
new file mode 100644
index 0000000..df403a6
--- /dev/null
+++ b/core/modules/image/meta/image.style.effects.__.yml
@@ -0,0 +1,11 @@
+name:
+  label: 'Style name'
+data:
+  label: 'Data'
+  type: 'config_subkeys'
+weight:
+  label: 'Weight'
+  type: 'integer'
+ieid:
+  label: 'IEID'
+  type: 'ieid'
diff --git a/core/modules/image/meta/image.style.effects.scale.yml b/core/modules/image/meta/image.style.effects.scale.yml
new file mode 100644
index 0000000..ad140c1
--- /dev/null
+++ b/core/modules/image/meta/image.style.effects.scale.yml
@@ -0,0 +1,9 @@
+data.width:
+  label: 'Width'
+  type: 'integer'
+data.height:
+  label: 'Height'
+  type: 'integer'
+data.upscale:
+  label: 'Upscale'
+  type: 'boolean'
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 385d6f4..846fd22 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -1998,6 +1998,26 @@ abstract class WebTestBase extends TestBase {
   }
 
   /**
+   * Wraps a data value into a typed data wrapper and executes some basic
+   * assertions.
+   *
+   * @see drupal_wrap_data().
+   */
+  protected function drupalWrapData($definition, $value = NULL, $context = array()) {
+    // Save the type that was passed in so we can compare with it later.
+    $type = $definition['type'];
+    // Construct the wrapper.
+    $wrapper = drupal_wrap_data($definition, $value, $context);
+    // Assert the definition of the wrapper.
+    $this->assertTrue($wrapper instanceof \Drupal\Core\TypedData\WrapperInterface, 'Wrapper is an instance of the wrapper interface.');
+    $definition = $wrapper->getDefinition();
+    $this->assertTrue(!empty($definition['label']), $definition['label'] . ' wrapper definition was returned.');
+    // Assert that the correct type was constructed.
+    $this->assertEqual($wrapper->getType(), $type, $definition['label'] . ' wrapper returned type.');
+    return $wrapper;
+  }
+
+  /**
    * Pass if the internal browser's URL matches the given path.
    *
    * @param $path
diff --git a/core/modules/system/lib/Drupal/system/Tests/TypedData/DataWrapperTest.php b/core/modules/system/lib/Drupal/system/Tests/TypedData/DataWrapperTest.php
new file mode 100644
index 0000000..23dd238
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/TypedData/DataWrapperTest.php
@@ -0,0 +1,130 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\TypedData\DataWrapperTest.
+ */
+
+namespace Drupal\system\Tests\TypedData;
+
+use Drupal\simpletest\WebTestBase;
+use DateTime;
+use DateInterval;
+
+/**
+ * Tests primitive data types.
+ */
+class DataWrapperTest extends WebTestBase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Test data wrappers',
+      'description' => 'Tests the functionality of all core data wrappers.',
+      'group' => 'Typed Data API',
+    );
+  }
+
+  /**
+   * Tests the basics around constructing and working with data wrappers.
+   */
+  public function testGetAndSet() {
+    // Boolean type.
+    $wrapper = $this->drupalWrapData(array('type' => 'boolean'), TRUE);
+    $this->assertTrue($wrapper->getValue() === TRUE, 'Boolean value was fetched.');
+    $wrapper->setValue(FALSE);
+    $this->assertTrue($wrapper->getValue() === FALSE, 'Boolean value was changed.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Boolean value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'Boolean wrapper is null-able.');
+
+    // String type.
+    $value = $this->randomString();
+    $wrapper = $this->drupalWrapData(array('type' => 'string'), $value);
+    $this->assertTrue($wrapper->getValue() === $value, 'String value was fetched.');
+    $new_value = $this->randomString();
+    $wrapper->setValue($new_value);
+    $this->assertTrue($wrapper->getValue() === $new_value, 'String value was changed.');
+    // Funky test.
+    $this->assertTrue(is_string($wrapper->getString()), 'String value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'String wrapper is null-able.');
+
+    // Integer type.
+    $value = rand();
+    $wrapper = $this->drupalWrapData(array('type' => 'integer'), $value);
+    $this->assertTrue($wrapper->getValue() === $value, 'Integer value was fetched.');
+    $new_value = rand();
+    $wrapper->setValue($new_value);
+    $this->assertTrue($wrapper->getValue() === $new_value, 'Integer value was changed.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Integer value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'Integer wrapper is null-able.');
+
+    // Decimal type.
+    $value = 123.45;
+    $wrapper = $this->drupalWrapData(array('type' => 'decimal'), $value);
+    $this->assertTrue($wrapper->getValue() === $value, 'Decimal value was fetched.');
+    $new_value = 678.90;
+    $wrapper->setValue($new_value);
+    $this->assertTrue($wrapper->getValue() === $new_value, 'Decimal value was changed.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Decimal value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'Decimal wrapper is null-able.');
+
+    // Date type.
+    $value = new DateTime('@' . REQUEST_TIME);
+    $wrapper = $this->drupalWrapData(array('type' => 'date'), $value);
+    $this->assertTrue($wrapper->getValue() === $value, 'Date value was fetched.');
+    $new_value = REQUEST_TIME + 1;
+    $wrapper->setValue($new_value);
+    $this->assertTrue($wrapper->getValue()->getTimestamp() === $new_value, 'Date value was changed and set by timestamp.');
+    $wrapper->setValue('2000-01-01');
+    $this->assertTrue($wrapper->getValue()->format('Y-m-d') == '2000-01-01', 'Date value was changed and set by date string.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Date value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'Date wrapper is null-able.');
+
+    // Duration type.
+    $value = new DateInterval('PT20S');
+    $wrapper = $this->drupalWrapData(array('type' => 'duration'), $value);
+    $this->assertTrue($wrapper->getValue() === $value, 'Duration value was fetched.');
+    $wrapper->setValue(10);
+    $this->assertTrue($wrapper->getValue()->s == 10, 'Duration value was changed and set by time span in seconds.');
+    $wrapper->setValue('P40D');
+    $this->assertTrue($wrapper->getValue()->d == 40, 'Duration value was changed and set by duration string.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Duration value was converted to string');
+    // Test getting the string and passing it back as value.
+    $duration = $wrapper->getString();
+    $wrapper->setValue($duration);
+    $this->assertEqual($wrapper->getString(), $duration, 'Duration formatted as string can be used to set the duration value.');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'Duration wrapper is null-able.');
+
+    // Generate some files that will be used to test the URI and the binary
+    // data types.
+    $files = $this->drupalGetTestFiles('image');
+
+    // URI type.
+    $wrapper = $this->drupalWrapData(array('type' => 'uri'), $files[0]->uri);
+    $this->assertTrue($wrapper->getValue() === $files[0]->uri, 'URI value was fetched.');
+    $wrapper->setValue($files[1]->uri);
+    $this->assertTrue($wrapper->getValue() === $files[1]->uri, 'URI value was changed.');
+    $this->assertTrue(is_string($wrapper->getString()), 'URI value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'URI wrapper is null-able.');
+
+    // Binary type.
+    $wrapper = $this->drupalWrapData(array('type' => 'binary'), $files[0]->uri);
+    $this->assertTrue(is_resource($wrapper->getValue()), 'Binary value was fetched.');
+    // Try setting by URI.
+    $wrapper->setValue($files[1]->uri);
+    $this->assertEqual(is_resource($wrapper->getValue()), fopen($files[1]->uri, 'r'), 'Binary value was changed.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Binary value was converted to string');
+    // Try setting by resource.
+    $wrapper->setValue(fopen($files[2]->uri, 'r'));
+    $this->assertEqual(is_resource($wrapper->getValue()), fopen($files[2]->uri, 'r'), 'Binary value was changed.');
+    $this->assertTrue(is_string($wrapper->getString()), 'Binary value was converted to string');
+    $wrapper->setValue(NULL);
+    $this->assertNull($wrapper->getValue(), 'Binary wrapper is null-able.');
+  }
+}
diff --git a/core/modules/system/meta/system.maintenance.yml b/core/modules/system/meta/system.maintenance.yml
new file mode 100644
index 0000000..0f4cd6d
--- /dev/null
+++ b/core/modules/system/meta/system.maintenance.yml
@@ -0,0 +1,6 @@
+enabled:
+  label: 'Put site into maintenance mode'
+  type: 'boolean'
+message:
+  label: 'Message to display when in maintenance mode'
+  type: 'string'
diff --git a/core/modules/system/meta/system.site.yml b/core/modules/system/meta/system.site.yml
new file mode 100644
index 0000000..f09e316
--- /dev/null
+++ b/core/modules/system/meta/system.site.yml
@@ -0,0 +1,21 @@
+name:
+  label: 'Site name'
+  type: 'string'
+mail:
+  label: 'Site mail'
+  type: 'email'
+slogan:
+  label: 'Site slogan'
+  type: 'string'
+page:
+  label: 'Error pages'
+  type: config_subkeys
+page.403:
+    label: 'Default 403 (access denied) page'
+    type: 'path'
+page.404:
+    label: 'Default 404 (not found) page'
+    type: 'path'
+page.front:
+    label: 'Default front page'
+    type: 'path'
\ No newline at end of file
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 135dc23..806e7f0 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -147,6 +147,63 @@ function hook_cron() {
 }
 
 /**
+ * Defines available data types for typed data wrappers.
+ *
+ * Typed data wrappers allow modules to support any kind of data based upon
+ * pre-defined primitive types and interfaces for data structures and lists.
+ *
+ * Defined data types may map to one of the pre-defined primitive types in
+ * \Drupal\Core\TypedData\Primitive or may be data structures, containing one or
+ * more data properties. Wrapper classes of data structures have to implement
+ * the \Drupal\Core\TypedData\StructureInterface. Further interfaces
+ * that may be implemented are:
+ *  - \Drupal\Core\TypedData\AccessibleInterface
+ *  - \Drupal\Core\TypedData\StructureTranslatableInterface
+ *
+ * Furthermore, lists of data items are represented with wrappers implementing
+ * the \Drupal\Core\TypedData\ListInterface, for which the class may be
+ * specified using the 'list class' key.
+ *
+ * @return array
+ *   An associative array where the key is the data type name and the value is
+ *   again an associative array. Supported keys are:
+ *   - label: The human readable label of the data type.
+ *   - class: The associated typed data wrapper class. Must implement the
+ *     \Drupal\Core\TypedData\WrapperInterface.
+ *   - list class: (optional) A typed data wrapper class used to wrap multiple
+ *     data items of the type. Must implement the
+ *     \Drupal\Core\TypedData\ListInterface.
+ *   - primitive type: (optional) Maps the data type to one of the pre-defined
+ *     primitive types in \Drupal\Core\TypedData\Primitive. If set, it must be
+ *     a constant defined by \Drupal\Core\TypedData\Primitive such as
+ *     \Drupal\Core\TypedData\Primitive::String.
+ *
+ * @see drupal_wrap_data()
+ * @see drupal_get_data_type_info()
+ */
+function hook_data_type_info() {
+  return array(
+    'email' => array(
+      'label' => t('Email'),
+      'class' => '\Drupal\email\Type\Email',
+      'primitive type' => \Drupal\Core\TypedData\Primitive::String,
+    ),
+  );
+}
+
+/**
+ * Alter available data types for typed data wrappers.
+ *
+ * @param array $data_types
+ *   An array of data type information.
+ *
+ * @see hook_data_type_info()
+ */
+function hook_data_type_info_alter(&$data_types) {
+  $data_types['email']['class'] = '\Drupal\mymodule\Type\Email';
+}
+
+/**
  * Declare queues holding items that need to be run periodically.
  *
  * While there can be only one hook_cron() process running at the same time,
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index e5dc768..4c6d18d 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Utility\ModuleInfo;
+use Drupal\Core\TypedData\Primitive;
 
 use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Response;
@@ -2004,6 +2005,105 @@ function system_stream_wrappers() {
 }
 
 /**
+ * Implements hook_data_type_info().
+ */
+function system_data_type_info() {
+  return array(
+    'boolean' => array(
+      'label' => t('Boolean'),
+      'class' => '\Drupal\Core\TypedData\Type\Boolean',
+      'primitive type' => Primitive::BOOLEAN,
+    ),
+    'string' => array(
+      'label' => t('String'),
+      'class' => '\Drupal\Core\TypedData\Type\String',
+      'primitive type' => Primitive::STRING,
+    ),
+    'integer' => array(
+      'label' => t('Integer'),
+      'class' => '\Drupal\Core\TypedData\Type\Integer',
+      'primitive type' => Primitive::INTEGER,
+    ),
+    'decimal' => array(
+      'label' => t('Decimal'),
+      'class' => '\Drupal\Core\TypedData\Type\Decimal',
+      'primitive type' => Primitive::DECIMAL,
+    ),
+    'date' => array(
+      'label' => t('Date'),
+      'class' => '\Drupal\Core\TypedData\Type\Date',
+      'primitive type' => Primitive::DATE,
+    ),
+    'duration' => array(
+      'label' => t('Duration'),
+      'class' => '\Drupal\Core\TypedData\Type\Duration',
+      'primitive type' => Primitive::DURATION,
+    ),
+    'uri' => array(
+      'label' => t('URI'),
+      'class' => '\Drupal\Core\TypedData\Type\Uri',
+      'primitive type' => Primitive::URI,
+    ),
+    'binary' => array(
+      'label' => t('Binary'),
+      'class' => '\Drupal\Core\TypedData\Type\Binary',
+      'primitive type' => Primitive::BINARY,
+    ),
+    'language' => array(
+      'label' => t('Language'),
+      'description' => t('A language object.'),
+      'class' => '\Drupal\Core\TypedData\Type\Language',
+    ),
+    'entity' => array(
+      'label' => t('Entity'),
+      'description' => t('All kind of entities, e.g. nodes, comments or users.'),
+      'class' => '\Drupal\Core\Entity\Property\EntityWrapper',
+    ),
+    'entity_translation' => array(
+      'label' => t('Entity translation'),
+      'description' => t('A translation of an entity'),
+      'class' => '\Drupal\Core\Entity\EntityTranslation',
+    ),
+    'boolean_item' => array(
+      'label' => t('Boolean item'),
+      'description' => t('An entity property containing a boolean value.'),
+      'class' => '\Drupal\Core\Entity\Property\BooleanItem',
+      'list class' => '\Drupal\Core\Entity\Property\ItemList',
+    ),
+    'string_item' => array(
+      'label' => t('String item'),
+      'description' => t('An entity property containing a string value.'),
+      'class' => '\Drupal\Core\Entity\Property\StringItem',
+      'list class' => '\Drupal\Core\Entity\Property\ItemList',
+    ),
+    'integer_item' => array(
+      'label' => t('Integer item'),
+      'description' => t('An entity property containing an integer value.'),
+      'class' => '\Drupal\Core\Entity\Property\IntegerItem',
+      'list class' => '\Drupal\Core\Entity\Property\ItemList',
+    ),
+    'date_item' => array(
+      'label' => t('Date item'),
+      'description' => t('An entity property containing a date value.'),
+      'class' => '\Drupal\Core\Entity\Property\DateItem',
+      'list class' => '\Drupal\Core\Entity\Property\ItemList',
+    ),
+    'language_item' => array(
+      'label' => t('Language item'),
+      'description' => t('An entity property referencing a language.'),
+      'class' => '\Drupal\Core\Entity\Property\LanguageItem',
+      'list class' => '\Drupal\Core\Entity\Property\ItemList',
+    ),
+    'entityreference_item' => array(
+      'label' => t('Entity reference item'),
+      'description' => t('An entity property containing an entity reference.'),
+      'class' => '\Drupal\Core\Entity\Property\EntityReferenceItem',
+      'list class' => '\Drupal\Core\Entity\Property\ItemList',
+    ),
+  );
+}
+
+/**
  * Retrieve a blocked IP address from the database.
  *
  * @param $iid integer
