diff --git a/core/includes/config.inc b/core/includes/config.inc
index 0011533..3d02bf6 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -297,3 +297,16 @@ function config_get_module_config_entities($module) {
     return ($entity_info['module'] == $module) && is_subclass_of($entity_info['class'], 'Drupal\Core\Config\Entity\ConfigEntityInterface');
   });
 }
+
+/**
+ * Returns the typed config manager service.
+ *
+ * Use the typed data manager service for creating typed configuration objects.
+ *
+ * @see Drupal\Core\TypedData\TypedDataManager::create()
+ *
+ * @return Drupal\Core\TypedData\TypedConfigManager
+ */
+function config_typed() {
+  return drupal_container()->get('config.typed');
+}
diff --git a/core/lib/Drupal/Core/Config/Schema/ArrayElement.php b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
new file mode 100644
index 0000000..3ac881a
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/ArrayElement.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\Schema\ArrayElement.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+use \ArrayAccess;
+use \ArrayIterator;
+use \Countable;
+use \IteratorAggregate;
+use \Traversable;
+
+/**
+ * Defines a generic configuration element.
+ */
+abstract class ArrayElement extends Element implements IteratorAggregate, ArrayAccess, Countable {
+
+  /**
+   * Parsed elements.
+   */
+  protected $elements;
+
+  /**
+   * Gets an array of contained elements.
+   *
+   * @return array
+   *   Array of \Drupal\Core\Config\Schema\ArrayElement objects.
+   */
+  protected function getElements() {
+    if (!isset($this->elements)) {
+      $this->elements = $this->parse();
+    }
+    return $this->elements;
+  }
+
+  /**
+   * Gets valid configuration data keys.
+   *
+   * @return array
+   *   Array of valid configuration data keys.
+   */
+  protected function getAllKeys() {
+    return is_array($this->value) ? array_keys($this->value) : array();
+  }
+
+  /**
+   * Builds an array of contained elements.
+   *
+   * @return array
+   *   Array of \Drupal\Core\Config\Schema\ArrayElement objects.
+   */
+  protected abstract function parse();
+
+  /**
+   * Implements TypedDataInterface::validate().
+   */
+  public function validate() {
+    foreach ($this->getElements() as $element) {
+      if (!$element->validate()) {
+        return FALSE;
+      }
+    }
+    return TRUE;
+  }
+
+  /**
+   * Implements ArrayAccess::offsetExists().
+   */
+  public function offsetExists($offset) {
+    return array_key_exists($offset, $this->getElements());
+  }
+
+  /**
+   * Implements ArrayAccess::offsetGet().
+   */
+  public function offsetGet($offset) {
+    $elements = $this->getElements();
+    return $elements[$offset];
+  }
+
+  /**
+   * Implements ArrayAccess::offsetSet().
+   */
+  public function offsetSet($offset, $value) {
+    if ($value instanceof TypedDataInterface) {
+      $value = $value->getValue();
+    }
+    $this->value[$offset] = $value;
+    unset($this->elements);
+  }
+
+  /**
+   * Implements ArrayAccess::offsetUnset().
+   */
+  public function offsetUnset($offset) {
+    unset($this->value[$offset]);
+    unset($this->elements);
+  }
+
+  /**
+   * Implements Countable::count().
+   */
+  public function count() {
+    return count($this->getElements());
+  }
+
+  /**
+   * Implements IteratorAggregate::getIterator();
+   */
+  public function getIterator() {
+    return new ArrayIterator($this->getElements());
+  }
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Config/Schema/Element.php b/core/lib/Drupal/Core/Config/Schema/Element.php
new file mode 100644
index 0000000..4143331
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/Element.php
@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\Schema\Element.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+use Drupal\Core\TypedData\Type\TypedData;
+
+/**
+ * Defines a generic configuration element.
+ */
+abstract class Element extends TypedData {
+
+  /**
+   * The configuration value.
+   *
+   * @var mixed
+   */
+  protected $value;
+
+  /**
+   * Constructor.
+   *
+   * @param \Drupal\Core\Config\Schema\Element $parent
+   *   Element's parent.
+   */
+  public function __construct($definition, $value, $parent = NULL) {
+    $this->value = $value;
+    $this->definition = $definition;
+    $this->parent = $parent;
+  }
+
+  /**
+   * Checks whether this element is translatable.
+   *
+   * @return bool
+   */
+  public function isTranslatable() {
+    return !empty($this->definition['translatable']);
+  }
+
+  /**
+   * Create typed config object.
+   */
+  protected function parseElement($key, $data, $definition) {
+    $context = array('name' => $key, 'parent' => $this);
+    return config_typed()->create($definition, $data, $context);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/Schema/Mapping.php b/core/lib/Drupal/Core/Config/Schema/Mapping.php
new file mode 100644
index 0000000..ba1d115
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/Mapping.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\Schema\Mapping.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use \InvalidArgumentException;
+
+/**
+ * Defines a mapping configuration element.
+ *
+ * Wraps configuration data and metadata allowing access to configuration data
+ * using the ComplexDataInterface API. This object may contain any number and
+ * type of nested properties.
+ */
+class Mapping extends ArrayElement implements ComplexDataInterface {
+
+  /**
+   * Overrides ArrayElement::parse()
+   */
+  protected function parse() {
+    $elements = array();
+    foreach ($this->definition['mapping'] as $key => $definition) {
+      if (isset($this->value[$key])) {
+        $elements[$key] = $this->parseElement($key, $this->value[$key], $definition);
+      }
+    }
+    return $elements;
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::get().
+   */
+  public function get($property_name) {
+    $elements = $this->getElements();
+    if (isset($elements[$property_name])) {
+      return $elements[$property_name];
+    }
+    else {
+      throw new InvalidArgumentException(format_string("The configuration property @key doesn't exist.", array(
+          '@key' => $property_name,
+      )));
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::set().
+   */
+  public function set($property_name, $value) {
+    // Set the data into the configuration array but behave according to the
+    // interface specification when we've got a null value.
+    if (isset($value)) {
+      $this->value[$property_name] = $value;
+      return $this->get($property_name);
+    }
+    else {
+      // In these objects, when clearing the value, the property is gone.
+      // As this needs to return a property, we get it before we delete it.
+      $property = $this->get($property_name);
+      unset($this->value[$property_name]);
+      $property->setValue($value);
+      return $property;
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::getProperties().
+   */
+  public function getProperties($include_computed = FALSE) {
+    return $this->getElements();
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::getPropertyValues().
+   */
+  public function getPropertyValues() {
+    return $this->getValue();
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::setPropertyValues().
+   */
+  public function setPropertyValues($values) {
+    foreach ($values as $name => $value) {
+      $this->value[$name] = $value;
+    }
+    return $this;
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinition().
+   */
+  public function getPropertyDefinition($name) {
+    if (isset($this->definition['mapping'][$name])) {
+      return $this->definition['mapping'][$name];
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
+   */
+  public function getPropertyDefinitions() {
+    $list = array();
+    foreach ($this->getAllKeys() as $key) {
+      $list[$key] = $this->getPropertyDefinition($key);
+    }
+    return $list;
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ComplexDataInterface::isEmpty().
+   */
+  public function isEmpty() {
+    return empty($this->value);
+  }
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Config/Schema/Parser.php b/core/lib/Drupal/Core/Config/Schema/Parser.php
new file mode 100644
index 0000000..db02963
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/Parser.php
@@ -0,0 +1,43 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\Schema\Parser.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+/**
+ * Parser.
+ */
+class Parser {
+
+  /**
+   * Parse configuration data against schema data.
+   */
+  static function parse($data, $definition, $context = array()) {
+    // Set default type depending on data and context.
+    if (!isset($definition['type'])) {
+      if (is_array($data) || !$context) {
+        $definition += array('type' => 'any');
+      }
+      else {
+        $definition += array('type' => 'str');
+      }
+    }
+    // Create typed data object.
+    config_typed()->create($definition, $data, $context);
+  }
+
+  /**
+   * Validate configuration data against schema data.
+   */
+  static function validate($config_data, $schema_data) {
+    return self::parse($config_data, $schema_data)->validate();
+  }
+
+  static function getDefinition($type, $data) {
+    return config_definition($type);
+  }
+}
+
diff --git a/core/lib/Drupal/Core/Config/Schema/Property.php b/core/lib/Drupal/Core/Config/Schema/Property.php
new file mode 100644
index 0000000..baade94
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/Property.php
@@ -0,0 +1,22 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\Schema\Sequence.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+/**
+ * Generic configuration property.
+ */
+class Property extends Element {
+
+  /**
+   * Implements TypedDataInterface::validate().
+   */
+  public function validate() {
+    return isset($this->value);
+  }
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Config/Schema/Schema.php b/core/lib/Drupal/Core/Config/Schema/Schema.php
new file mode 100644
index 0000000..e69de29
diff --git a/core/lib/Drupal/Core/Config/Schema/SchemaDiscovery.php b/core/lib/Drupal/Core/Config/Schema/SchemaDiscovery.php
new file mode 100644
index 0000000..f4ffd7a
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/SchemaDiscovery.php
@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Config\Schema\SchemaDiscovery.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
+use Drupal\Component\Utility\NestedArray;
+
+/**
+ * A discovery mechanism that reads plugin definitions from schema data
+ * in YAML format.
+ */
+class SchemaDiscovery implements DiscoveryInterface {
+
+  /**
+   * A storage controller instance for reading configuration schema data.
+   *
+   * @var Drupal\Core\Config\StorageInterface
+   */
+  protected $storage;
+
+  /**
+   * The array of plugin definitions, keyed by plugin id.
+   *
+   * @var array
+   */
+  protected $definitions = array();
+
+  /**
+   * Public constructor.
+   *
+   * @param Drupal\Core\Config\StorageInterface $storage
+   *   The storage controller object to use for reading schema data
+   */
+  public function __construct($storage) {
+    $this->storage = $storage;
+    // Load definitions for all enabled modules.
+    foreach (module_list() as $module) {
+      $this->loadSchema($module);
+    }
+    // @todo Load definitions for all enabled themes.
+
+  }
+
+  /**
+   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinition().
+   */
+  public function getDefinition($base_plugin_id) {
+    if (isset($this->definitions[$base_plugin_id])) {
+      $type = $base_plugin_id;
+    }
+    elseif (strpos($base_plugin_id, '.') && ($name = $this->getFallbackName($base_plugin_id)) && isset($this->definitions[$name])) {
+      // Found a generic name, replacing the last element by '%'
+      $type = $name;
+    }
+    else {
+      // If we don't have definition, return the 'unknown' element.
+      // This should map to 'any' type by default, unless overridden.
+      $type = 'default';
+    }
+    $definition = $this->definitions[$type];
+    // Check whether this type is an extension of another one and compile it.
+    if (isset($definition['type'])) {
+      $merge = $this->getDefinition($definition['type']);
+      $definition = NestedArray::mergeDeep($merge, $definition);
+      // Unset type so we try the merge only once per type.
+      unset($definition['type']);
+      $this->definitions[$type] = $definition;
+    }
+    return $definition;
+  }
+
+  /**
+   * Implements Drupal\Component\Plugin\Discovery\DiscoveryInterface::getDefinitions().
+   */
+  public function getDefinitions() {
+    return $this->definitions;
+  }
+
+  /**
+   * Load schema for module / theme.
+   */
+  protected function loadSchema($component) {
+    if ($schema = $this->storage->read($component . '.schema')) {
+      foreach ($schema as $type => $definition) {
+        $this->definitions[$type] = $definition;
+
+      }
+    }
+  }
+
+  /**
+   * Gets fallback metadata name.
+   *
+   * @param string $name
+   *   Configuration name or key.
+   *
+   * @return string
+   *   Same name with the last part replaced by the filesystem marker.
+   */
+  protected static function getFallbackName($name) {
+    $replaced = preg_replace('/\.[^.]+$/', '.' . '%', $name);
+    if ($replaced != $name) {
+      return $replaced;
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/Config/Schema/Sequence.php b/core/lib/Drupal/Core/Config/Schema/Sequence.php
new file mode 100644
index 0000000..73b196c
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/Schema/Sequence.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\Schema\Sequence.
+ */
+
+namespace Drupal\Core\Config\Schema;
+
+use Drupal\Core\TypedData\ListInterface;
+
+/**
+ * Defines a configuration element of type Sequence.
+ */
+class Sequence extends ArrayElement implements ListInterface {
+
+  /**
+   * Overrides ArrayElement::parse()
+   */
+  protected function parse() {
+    $definition = $this->definition['sequence'][0];
+    $elements = array();
+    foreach ($this->value as $key => $value) {
+      $elements[$key] = $this->parseElement($key, $value, $definition);
+    }
+    return $elements;
+  }
+
+  /**
+   * Implements Drupal\Core\TypedData\ListInterface::isEmpty().
+   */
+  public function isEmpty() {
+    return empty($this->value);
+  }
+
+}
\ No newline at end of file
diff --git a/core/lib/Drupal/Core/Config/TypedConfigManager.php b/core/lib/Drupal/Core/Config/TypedConfigManager.php
new file mode 100644
index 0000000..9ef0d4b
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/TypedConfigManager.php
@@ -0,0 +1,149 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Config\TypedConfigManager.
+ */
+
+namespace Drupal\Core\Config;
+
+use Drupal\Core\Config\Schema\SchemaDiscovery;
+use Drupal\Core\TypedData\TypedDataManager;
+use Drupal\Core\TypedData\TypedDataFactory;
+
+/**
+ * Manages config type plugins.
+ */
+class TypedConfigManager extends TypedDataManager {
+
+  /**
+   * A storage controller instance for reading configuration data.
+   *
+   * @var Drupal\Core\Config\StorageInterface
+   */
+  protected $storage;
+
+  /**
+   * Creates a new typed configuration manager.
+   *
+   * @param Drupal\Core\Config\StorageInterface $storage
+   *   The storage controller object to use for reading schema data
+   */
+  public function __construct($storage) {
+    $this->storage = $storage;
+    $this->discovery = new SchemaDiscovery($storage);
+    $this->factory = new TypedDataFactory($this->discovery);
+  }
+
+  /**
+   * Gets typed configuration data.
+   *
+   * @param string $name
+   *   Configuration object name.
+   *
+   * @return Drupal\Core\Config\Schema\Element
+   *   Typed configuration element.
+   */
+  public function get($name) {
+    $data = $this->storage->read($name);
+    $definition = $this->getDefinition($name);
+    return $this->create($definition, $data);
+  }
+
+  /**
+   * Overrides Drupal\Core\TypedData\TypedDataManager::create()
+   *
+   * Fills in default type and does variable replacement.
+   */
+  public function create(array $definition, $value = NULL, array $context = array()) {
+    if (!isset($definition['type'])) {
+      // Set default type 'str' if possible. If not it will be 'any'.
+      if (is_string($value)) {
+        $definition['type'] = 'str';
+      }
+      else {
+        $definition['type'] = 'any';
+      }
+    }
+    elseif (strpos($definition['type'], ']')) {
+      // Replace variable names in definition.
+      $replace = is_array($value) ? $value : array();
+      if ($context) {
+        $replace['%parent'] = $context['parent']->getValue();
+        $replace['%key'] = $context['name'];
+      }
+      $definition['type'] = $this->replaceName($definition['type'], $replace);
+    }
+    // Create typed config object.
+    return parent::create($definition, $value, $context);
+  }
+
+  /**
+   * Replaces variables in configuration name.
+   *
+   * The configuration name may contain one or more variables to be replaced,
+   * enclosed in square brackets like '[name]' and will follow the replacement
+   * rules defined by the replaceVariable() method.
+   *
+   * @param string $name
+   *   Configuration name with variables in square brackets.
+   * @param mixed $data
+   *   Configuration data for the element.
+   * @return string
+   *   Configuration name with variables replaced.
+   */
+  protected static function replaceName($name, $data) {
+    if (preg_match_all("/\[(.*)\]/U", $name, $matches)) {
+      // Build our list of '[value]' => replacement.
+      foreach (array_combine($matches[0], $matches[1]) as $key => $value) {
+        $replace[$key] = self::replaceVariable($value, $data);
+      }
+      return strtr($name, $replace);
+    }
+    else {
+      return $name;
+    }
+  }
+
+  /**
+   * Replaces variable values in included names with configuration data.
+   *
+   * Variable values are nested configuration keys that will be replaced by
+   * their value or some of these special strings:
+   * - '%key', will be replaced by the element's key.
+   * - '%parent', to reference the parent element.
+   *
+   * There may be nested configuration keys separated by dots or more complex
+   * patterns like '%parent.name' which references the 'name' value of the
+   * parent element.
+   *
+   * Example patterns:
+   * - 'name.subkey', indicates a nested value of the current element.
+   * - '%parent.name', will be replaced by the 'name' value of the parent.
+   * - '%parent.%key', will be replaced by the parent element's key.
+   *
+   * @param string $value
+   *   Variable value to be replaced.
+   *
+   * @return string
+   *   The replaced value if a replacement found or the original value if not.
+   */
+  protected static function replaceVariable($value, $data) {
+    $parts = explode('.', $value);
+    // Process each value part, one at a time.
+    while ($name = array_shift($parts)) {
+      if (!is_array($data) || !isset($data[$name])) {
+        // Key not found, return original value
+        return $value;
+      }
+      elseif (!$parts) {
+        // If no more parts left, this is the final property.
+        return (string)$data[$name];
+      }
+      else {
+        // Get nested value and continue processing.
+        $data = $data[$name];
+      }
+    }
+  }
+}
diff --git a/core/lib/Drupal/Core/CoreBundle.php b/core/lib/Drupal/Core/CoreBundle.php
index 8300fc3..5c7c934 100644
--- a/core/lib/Drupal/Core/CoreBundle.php
+++ b/core/lib/Drupal/Core/CoreBundle.php
@@ -63,6 +63,10 @@ public function build(ContainerBuilder $container) {
       ->register('config.storage.staging', 'Drupal\Core\Config\FileStorage')
       ->addArgument(config_get_config_directory(CONFIG_STAGING_DIRECTORY));
 
+    // Register the typed configuration data manager.
+    $container->register('config.typed', 'Drupal\Core\Config\TypedConfigManager')
+      ->addArgument(new Reference('config.storage'));
+
     // Register the service for the default database connection.
     $container->register('database', 'Drupal\Core\Database\Connection')
       ->setFactoryClass('Drupal\Core\Database\Database')
diff --git a/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
new file mode 100644
index 0000000..46dac7f
--- /dev/null
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigSchemaTest.php
@@ -0,0 +1,141 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\config\Tests\ConfigMetadataTest.
+ */
+
+namespace Drupal\config\Tests;
+
+use Drupal\Core\Config\TypedConfig;
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests schema for configuration objects.
+ */
+class ConfigSchemaTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('locale', 'image');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Configuration schema',
+      'description' => 'Tests Metadata for configuration objects.',
+      'group' => 'Configuration',
+    );
+  }
+
+  /**
+   * Tests the basic metadata retrieval layer.
+   */
+  function testSchemaMapping() {
+    // Simple case, straight metadata.
+    $definition = config_typed()->getDefinition('system.maintenance');
+    $expected = array();
+    $expected['label'] = 'Maintenance mode';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['mapping']['enabled'] = array(
+      'label' => 'Put site into maintenance mode',
+      'type' => 'bool'
+    );
+    $expected['mapping']['message'] = array(
+      'label' =>  'Message to display when in maintenance mode',
+      'type' => 'text',
+    );
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for system.maintenance');
+
+    // More complex case, generic type. Metadata for image style.
+    $definition = config_typed()->getDefinition('image.style.large');
+    $expected = array();
+    $expected['label'] = 'Image style';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['mapping']['name']['type'] = 'str';
+    $expected['mapping']['label']['type'] = 'label';
+    $expected['mapping']['effects']['type'] = 'seq';
+    $expected['mapping']['effects']['sequence'][0]['type'] = 'map';
+    $expected['mapping']['effects']['sequence'][0]['mapping']['name']['type'] = 'str';
+    $expected['mapping']['effects']['sequence'][0]['mapping']['data']['type'] = 'image.effect.[%parent.name]';
+    $expected['mapping']['effects']['sequence'][0]['mapping']['weight']['type'] = 'weight';
+    $expected['mapping']['effects']['sequence'][0]['mapping']['ieid']['type'] = 'str';
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.style.large');
+
+    // More complex, type based on a complex one.
+    $definition = config_typed()->getDefinition('image.effect.image_scale');
+    // This should be the schema for image.effect.image_scale.
+    $expected = array();
+    $expected['label'] = 'Image scale';
+    $expected['class'] = '\Drupal\Core\Config\Schema\Mapping';
+    $expected['mapping']['width']['type'] = 'int';
+    $expected['mapping']['width']['label'] = 'Width';
+    $expected['mapping']['height']['type'] = 'int';
+    $expected['mapping']['height']['label'] = 'Height';
+    $expected['mapping']['upscale']['type'] = 'bool';
+    $expected['mapping']['upscale']['label'] = 'Upscale';
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for image.effect.image_scale');
+
+    // Most complex case, get metadata for actual configuration element.
+    $effects = config_typed()->get('image.style.medium')->get('effects');
+    $definition = $effects['bddf0d06-42f9-4c75-a700-a33cafa25ea0']['data']->getDefinition();
+    // This should be the schema for image.effect.image_scale, reuse previous one.
+    $expected['type'] =  'image.effect.image_scale';
+
+    $this->assertEqual($definition, $expected, 'Retrieved the right metadata for the first effect of image.style.medium');
+  }
+
+  /**
+   * Tests metadata applied to configuration objects.
+   */
+  function testSchemaData() {
+    // Try some simple properties.
+    $meta = config_typed()->get('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(), 'label', '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')->get('front');
+    $this->assertTrue(is_a($property, 'Drupal\Core\TypedData\Type\String'), 'Got the right wrapper fo the page.front property.');
+    $this->assertEqual($property->getType(), 'path', 'Got the right type for page.front data (undefined).');
+    $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.');
+
+    // And test some ComplexDataInterface methods.
+    $properties = $list->getProperties();
+    $this->assertTrue(count($properties) == 3 && $properties['front'] == $list['front'], 'Got the right properties for site page.');
+    $values = $list->getPropertyValues();
+    $this->assertTrue(count($values) == 3 && $values['front'] == 'user', 'Got the right property values for site page.');
+
+    // Now let's try something more complex, with nested objects.
+    $wrapper = config_typed()->get('image.style.large');
+    $effects = $wrapper->get('effects');
+
+    // The function is_array() doesn't work with ArrayAccess, so we use count().
+    $this->assertTrue(count($effects) == 1, 'Got an array with effects for image.style.large data');
+    $ieid = key($effects->getValue());
+    $effect = $effects[$ieid];
+    $this->assertTrue(count($effect['data']) && $effect['name']->getValue() == 'image_scale', 'Got data for the image scale effect from metadata.');
+    $this->assertEqual($effect['data']['width']->getType(), 'int', '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 = config_typed()->get('system.site');
+    $wrapper->set('slogan', $new_slogan);
+    $site_slogan = $wrapper->get('slogan');
+    $this->assertEqual($site_slogan->getValue(), $new_slogan, 'Successfully updated the contained configuration data');
+  }
+
+}
+
diff --git a/core/modules/contact/config/contact.schema.yml b/core/modules/contact/config/contact.schema.yml
new file mode 100644
index 0000000..d1c92c2
--- /dev/null
+++ b/core/modules/contact/config/contact.schema.yml
@@ -0,0 +1,35 @@
+# Contact module schema: contact.schema.yml
+
+# Schema for contact category (multiple)
+contact.category.%:
+  type: map
+  mapping:
+    "id":
+      type: str
+    "label":
+      type: str
+    "recipients":
+      type: seq
+      sequence:
+        - type: str
+    "reply":
+      type: str
+    "weight":
+      type: int
+      
+# Module settings
+contact.settings:
+  type: map
+  mapping:
+    "default_category":
+      type: str
+      required: yes
+    "flood":
+      type: map
+      mapping:
+        "limit":
+          type: int
+        "interval":
+          type: int
+     "user_default_enabled":
+       type: bool
\ No newline at end of file
diff --git a/core/modules/image/config/image.schema.yml b/core/modules/image/config/image.schema.yml
new file mode 100644
index 0000000..5cba17d
--- /dev/null
+++ b/core/modules/image/config/image.schema.yml
@@ -0,0 +1,83 @@
+# Image module schema: image.schema.yml
+
+# Image data types.
+image.size:
+  type: map
+  mapping:
+    "width":
+      type: int
+      label: "Width"
+    "height":
+      type: int
+      label: "Height"
+   
+# Image module settings.
+image.settings:
+  type: map
+  mapping:
+    "preview_image":
+      type: str
+      label: "Preview image"
+
+# Image styles (multiple).
+image.style.%:
+  type: map
+  label: "Image style"
+  mapping:
+    "name":
+      type: str
+    "label":
+      type: label
+    "effects":
+      type: seq
+      sequence:
+        - type: map
+          mapping:
+            "name":
+              type: str
+            "data":
+              type: image.effect.[%parent.name]
+            "weight":
+              type: weight
+            "ieid":
+              type: str
+
+# Image effects plugins: image.effect.%
+
+image.effect.image_crop:
+  type: image.size
+  label: "Image crop"
+  mapping:
+    "anchor":
+      label: "Anchor"
+      
+image.effect.image_resize:
+  type: image.size
+  label: "Image resize"
+  
+image.effect.image_rotate:
+  type: map
+  label: "Image rotate"
+  mapping:
+    degrees:
+      type: int
+      label: 'Rotation angle'
+    bgcolor:
+      label: 'Background color'
+    random:
+      type: bool
+      label: 'Randomize'
+
+image.effect.image_scale:
+  type: image.size
+  label: "Image scale"
+  mapping:
+    "upscale":
+      type: bool
+      label: "Upscale"
+
+image.effect.image_scale_and_crop:
+  type: image.size
+  label: "Image scale and crop"
+
+ 
\ No newline at end of file
diff --git a/core/modules/system/config/system.schema.yml b/core/modules/system/config/system.schema.yml
new file mode 100644
index 0000000..670fb4e
--- /dev/null
+++ b/core/modules/system/config/system.schema.yml
@@ -0,0 +1,101 @@
+# Basic scalar data types (Kwalify).
+any:
+  label: 'Undefined'
+  class: '\Drupal\Core\Config\Schema\Property'
+bool:
+  label: 'Boolean'
+  class: '\Drupal\Core\TypedData\Type\Boolean'
+int:
+  label: 'Integer'
+  class: '\Drupal\Core\TypedData\Type\Integer'
+scalar:
+  label: 'Scalar'
+  class: '\Drupal\Core\Config\Schema\Property'
+str:
+  label: 'String'
+  class: '\Drupal\Core\TypedData\Type\String'
+
+# Basic array data types (Kwalify).
+map:
+  label: Mapping
+  class: '\Drupal\Core\Config\Schema\Mapping'
+seq:
+  label: Sequence
+  class: '\Drupal\Core\Config\Schema\Sequence'
+
+# Simple scalar data types (Drupal)
+label:
+  type: str
+  label: 'Label'
+  length:     { max: 255, min: 0 }
+  translatable: true
+path:
+  type: str
+  label: 'Path'
+  class: '\Drupal\Core\TypedData\Type\String'
+text:
+  type: str
+  label: 'Text'
+  translatable: true
+weight:  
+  type: int
+  label: 'Weight'
+  range: { max: 255, min: -255 }
+
+# Mapping for types not found.
+default:
+  type: any
+  label: 'Unknown'
+
+# Complex data types.
+mail:  
+  type: map
+  label: "Mail"
+  mapping:
+    "subject":
+      type: text
+      label: "Subject"
+    "body":
+      type: text
+      label: "Body"
+  
+# System module settings.
+system.site:
+  type: map
+  label: 'Site information'
+  mapping:
+    "name":
+      label: "Site name"
+      type: label
+    "mail":
+      label: "Site mail"
+      type: str
+    "slogan":
+      label: "Site slogan"
+      type: text
+    "page":
+      type: map
+      mapping:
+        "403":
+          type: path
+        "404":
+          type: path
+        "front":
+          type: path
+          label: "Front page path"
+    "admin_compact_mode":
+      type: bool
+    "weight_select_max":
+      type: int
+
+system.maintenance:
+  type: map
+  label: 'Maintenance mode'
+  mapping:
+    "enabled":
+      type: bool
+      label: "Put site into maintenance mode"
+    "message":
+      type: text
+      label: "Message to display when in maintenance mode"
+      
\ No newline at end of file
diff --git a/core/modules/user/config/user.schema.yml b/core/modules/user/config/user.schema.yml
new file mode 100644
index 0000000..b40da69
--- /dev/null
+++ b/core/modules/user/config/user.schema.yml
@@ -0,0 +1,75 @@
+# User module schema: user.schema.yml
+
+# User mails.
+user.mail:
+ type: map
+ mapping:
+  "cancel_confirm":
+    type: mail
+    label: "Account cancellation confirmation"
+  "password_reset":
+    type: mail
+    label: "Password reset email"
+  "register_admin_created":
+    type: mail
+    label: "Account created by administrator"
+  "register_no_approval_required":
+    type: mail
+    label: "Registration confirmation (No approval required)"
+  "register_pending_approval":
+    type: mail
+    label: "Registration confirmation (Pending approval)"
+  "status_activated":
+    type: mail
+    label: "Account activation"
+  "status_blocked":
+    type: mail
+    label: "Account blocked"
+  "status_canceled":
+    type: mail
+    label: "Account cancelled"
+
+# User settings.
+user.settings:
+  type: map
+  mapping:
+    "admin_role":
+      type: str
+      label: "Administrator role"
+    "anonymous":
+      type: label
+      label: "Anonymous name"
+    "verify_mail":
+      type: bool
+      label: "Verify mail"
+    "notify":
+      type: map
+      label: "Notify user"
+      mapping:
+        "cancel_confirm":
+          type: bool
+        "password_reset":
+          type: bool
+        "status_activated":
+          type: bool
+        "status_blocked":
+          type: bool
+        "status_cancelled":
+          type: bool
+        "register_admin_created":
+          type: bool
+        "register_no_approval_required":
+          type: bool
+        "register_pending_approval":
+          type: bool
+    "register":
+      type: str
+      enum: [visitors, admin_only, visitors_admin_approval]
+    "signatures":
+      type: bool
+      label: "User signatures"
+    "cancel_method":
+      type: str
+      label: "User cancel method"
+    "password_reset_timeout":
+      type: int
diff --git a/core/modules/views/config/views.schema.yml b/core/modules/views/config/views.schema.yml
new file mode 100644
index 0000000..4c8e386
--- /dev/null
+++ b/core/modules/views/config/views.schema.yml
@@ -0,0 +1,232 @@
+# View definition (multiple)
+views.view.%:
+  type: map
+  label: 'View'
+  mapping:
+    disabled:
+      type: bool
+      label: 'Disabled'
+    api_version:
+      label: 'API version'
+    module:
+      label: 'Module'
+    name:
+      label: 'Machine name'
+    description:
+      type: text
+      label: 'Administrative description'
+    tag:
+      label: 'Tag'
+    base_table:
+      label: 'Base table'
+    base_field:
+      label: 'Base field'
+    human_name:
+      type: label
+      label: 'Human readable name'
+    core:
+      label: 'Drupal version'
+    uuid:
+      label: 'UUID' 
+    display:
+      type: seq
+      label: 'Displays'
+      sequence:
+        - type: map
+          label: 'Display settings'
+          mapping:      
+            id:
+              label: 'Machine name'
+            display_title:
+              type: text
+              label: 'Title'
+            display_plugin:
+              label: 'Display plugin'
+            position:
+              type: int
+              label: 'Position'
+            display_options:
+              type: 'views.display.[%parent.display_plugin]'
+
+# Views display: common
+# Options for Drupal\views\Plugin\views\display\DisplayPluginBase
+views.display.%:
+  type: map
+  label: 'Display options'
+  mapping:
+    title:
+      type: text
+      label: 'Display title'
+    format:
+      label: 'Format'
+    fields:
+      type: seq
+      label: 'Fields'
+      sequence:
+        - type: 'views.field.[table]-[field]'
+    pager:
+      type: map
+      label: 'Pager'
+      mapping:
+        type:
+          label: 'Pager type'
+        options:
+          type: map
+          label: 'Options'
+          mapping:
+            offset:
+              type: int
+              label: 'Offset'
+  
+    exposed_form:
+      type: map
+      label: 'Exposed form'
+      mapping:
+        type:
+          label: 'Exposed form type'   
+    access:
+      type: map
+      label: 'Access'
+      mapping:
+        type:
+          label: 'Access type'
+    other:
+      label: 'Other'
+    cache:
+      type: map
+      label: 'Cache'
+      mapping:
+        type:
+          label: 'Cache type'
+    sorts:
+      type: seq
+      label: 'Sorts'
+      sequence:
+        - type: 'views.sort.[table]-[field]'    
+    arguments:
+      type: seq
+      label: 'Arguments'
+      sequence:
+        - type: 'views.argument.[table]-[field]'
+    filters:
+      type: seq
+      label: 'Filters'
+      sequence:
+        - type: 'views.filter.[table]-[field]'
+    style:
+      type: map
+      label: 'Style'
+      mapping:
+        type:
+          label: 'Type'
+    row:
+      type: map
+      label: 'Row'
+      mapping:
+        type:
+          label: 'Row type'
+        options:
+          include: 'views.row.[%parent.type]'
+    query:
+      type: map
+      label: 'Query'
+      mapping:
+        type:
+          label: 'Query type'
+        options:
+          type: map
+          label: 'Query options'
+          mapping:
+            query_comment:
+              type: bool
+              label: 'Query comment'
+    defaults:
+      type: map
+      label: 'Defaults'
+      mapping:
+        style_plugin:
+          label: 'Style plugin'
+        style_options:
+          type: 'views.style.[%parent.style_plugin]'
+        row_plugin:
+          label: 'Row plugin'
+        row_options:
+          type: 'views.style.[%parent.row_plugin]'
+    relationships:
+      type: seq
+      label: 'Relationships'
+      sequence:
+        - type: 'views.relationship.[table]-[field]'  
+
+# Options for Drupal\views\Plugin\views\display\PathPluginBase
+views.display.PathPluginBase:
+  include: 'views.display.%'
+  type: map
+  mapping:
+    path:
+      type: str
+      label: 'Page path'
+
+# Views display plugin: Drupal\views\Plugin\views\display\Page
+views.display.page:
+  type: 'views.display.PathPluginBase'
+  label: 'Page display options'
+  mapping:
+    menu:
+      type: map
+      label: 'Menu'
+      mapping:
+        type:
+          label: 'Type'
+        title:
+          type: text
+          label: 'Title'
+        description:
+          type: text
+          label: 'Description'
+        weight:
+          type: integer
+          label: 'Weight'
+        name:
+          label: 'Menu name'
+        context:
+          label: 'Context'
+    tab_options:
+      type: map
+      label: 'Tab options'
+      mapping:
+        type:
+          label: 'Type'
+        title:
+          type: text
+          label: 'Title'
+        description:
+          type: text
+          label: 'Description'
+        weight:
+          type: int
+          label: 'Weight'
+        name:
+          label: 'Menu name'
+ 
+# Views display plugin: Drupal\views\Plugin\views\display\Block
+views.display.block:
+  type: 'views.display.%'
+  label: 'Block display options'
+  mapping:
+    block_description:
+      type: text
+      label: 'Block name'
+    block_caching:
+      label: 'Block caching'
+ 
+# Views display plugin: Drupal\views\Plugin\views\display\Feed
+views.display.feed:
+  type: 'views.display.PathPluginBase'
+  label: 'Feed display options'
+  mapping:
+    sitename_title:
+      type: bool
+      label: 'Use the site name for the title'
+    displays:
+      label: 'The feed icon will be available only to the selected displays.'
