diff --git a/core/includes/config.inc b/core/includes/config.inc
index 347bf85..961c591 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -1,9 +1,11 @@
 <?php
 
+use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Config\Config;
 use Drupal\Core\Config\FileStorage;
 use Drupal\Core\Config\NullStorage;
 use Drupal\Core\Config\StorageInterface;
+use Drupal\Core\Config\FileStorageReadException;
 
 /**
  * @file
@@ -105,6 +107,147 @@ function config_sync_get_changes(StorageInterface $source_storage, StorageInterf
 }
 
 /**
+ * Retrieves metadata for a configuration object or key.
+ *
+ * The configuration name may contain the placeholder '*' which means generic
+ * configuration for all objects of this type. If it does not contain it, we
+ * load first the generic metadata and add specific configuration for this type
+ * on top of it.
+ *
+ * Example: For image.style.large
+ * 1. Load metadata for image.style.*
+ * 2. Merge metadata for image.style.large
+ *
+ * @param $name
+ *   Configuration name.
+ * @param $key
+ *   Configuration key.
+ */
+function config_meta_data($name, $key = '') {
+  $meta = &drupal_static(__FUNCTION__);
+  if (!isset($meta[$name])) {
+    $meta[$name] = array();
+    // Get first part of name that will determine the module that owns this configuration.
+    $parts = explode('.', $name);
+    $module = $parts[0];
+    // We are looking for a file in $module/meta/$name.yml
+    $module_meta_dir = drupal_get_path('module', $module) . '/meta';
+    if (is_dir($module_meta_dir)) {
+      // If the name doesn't contain '*', start with the generic data
+      $last = array_pop($parts);
+      if ($last != '*') {
+        // Try name ended in * if this one does not exist.
+        $base_name = implode('.', array_merge($parts, array('*')));
+        $meta[$name] = config_meta_data($base_name);
+      }
+      try {
+        $storage = new Filestorage(array('directory' => $module_meta_dir));
+        if ($data = $storage->read($name)) {
+          $meta[$name] = NestedArray::mergeDeep($meta[$name], $data);
+        }
+      }
+      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.
+      }
+    }
+  }
+  if ($key) {
+    return isset($meta[$name][$key]) ? $meta[$name][$key] : array();
+  }
+  return $meta[$name];
+}
+
+/**
+ * Build nested configuration properties.
+ */
+function config_meta_build($name, $data) {
+  $meta = config_meta_data($name);
+  $build = _config_meta_match($meta, $data);
+  return $build;
+}
+
+/**
+ * Match configuration metadata against real configuration data.
+ */
+function _config_meta_match($meta, $data, $name = '', $prefix = '', $group = '') {
+  $build = array();
+  foreach ($data as $key => $value) {
+    $index = config_build_name($prefix, $key);
+    if (!isset($meta[$index])) {
+      // Default element type when we have no metadata.
+      $build += _config_meta_element(array('type' => 'value'), $value, $name, $key, $group);
+    }
+    elseif (!empty($meta[$index]['subkeys'])) {
+      // First build the base element, then build each element
+      $build += _config_meta_element($meta[$index], NULL, $name, $key, $group);
+      // Nested elements, find subkeys in the file, the current key will be the prefix.
+      $group_name = config_build_name($name, $key);
+      $build += _config_meta_match($meta, $value, $group_name, $key, $group_name);
+    }
+    else {
+      $build += _config_meta_element($meta[$index], $value, $name, $key, $group);
+    }
+  }
+  return $build;
+}
+
+/**
+ * Build configuration element with data and metadata.
+ *
+ * @param $base
+ *   Base name for this element.
+ * @param $index
+ *   Index of this element in the data array.
+ *
+ */
+function _config_meta_element($meta, $data, $base, $index, $group = '') {
+  $build = array();
+  $name = config_build_name($base, $index);
+  if ($meta['type'] == 'nested_config') {
+    $build[$name] = $meta;
+    // 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.
+    foreach ($data as $key => $value) {
+      if (isset($value['name'])) {
+        $meta_name = $value['name'];
+      }
+      else {
+        $meta_name = $meta['config_name'];
+      }
+      $element_meta = config_meta_data($meta_name);
+      $build += _config_meta_match($element_meta, $value, config_build_name($name, $key), NULL, config_build_name($group, $name));
+    }
+  }
+  else {
+    // End element, set data as value.
+    if ($group) {
+      $meta += array('group' => $group);
+    }
+    if (isset($data)) {
+      $meta += array('value' => $data);
+    }
+    $build[$name] = $meta;
+  }
+
+  return $build;
+}
+
+/**
+ * Helper function to build names in the configuration system.
+ *
+ * This function accepts any number of strings as arguments, and implodes them,
+ * placing a period (.) in between. It takes care of filtering out empty
+ * empty strings, so that the result does not contain double periods.
+ */
+function config_build_name() {
+  $args = func_get_args();
+  return implode('.', array_filter($args));
+}
+
+/**
  * Writes an array of config file changes from a source storage to a target storage.
  *
  * @param array $config_changes
diff --git a/core/modules/image/config/image.style.large.yml b/core/modules/image/config/image.style.large.yml
index e4f2e1f..df8daa8 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:
     image_scale_480_480_1:
-        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 17196b4..b26c71f 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:
     image_scale_220_220_1:
-        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 2e6b9c4..c44308d 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:
     image_scale_100_100_1:
-        name: image_scale
+        name: image.style.effects.scale
         data:
             width: '100'
             height: '100'
diff --git a/core/modules/image/image.api.php b/core/modules/image/image.api.php
index 758d38b..1fc523a 100644
--- a/core/modules/image/image.api.php
+++ b/core/modules/image/image.api.php
@@ -179,12 +179,12 @@ function hook_image_default_styles() {
   $styles['mymodule_preview'] = array(
     'effects' => array(
       array(
-        'name' => 'image_scale',
+        'name' => 'image.style.effects.scale',
         'data' => array('width' => 400, 'height' => 400, 'upscale' => 1),
         'weight' => 0,
       ),
       array(
-        'name' => 'image_desaturate',
+        'name' => 'image.style.effects.desaturate',
         'data' => array(),
         'weight' => 1,
       ),
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 12d845c..f3a4869 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',
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageDimensionsTest.php
index d2554cf..c3d141f 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..79226bb
--- /dev/null
+++ b/core/modules/image/meta/image.style.*.yml
@@ -0,0 +1,7 @@
+name:
+  title: 'Machine name'
+  type: 'machine_name'
+effects:
+  title: 'Style effects'
+  type: 'nested_config'
+  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..672db16
--- /dev/null
+++ b/core/modules/image/meta/image.style.effects.*.yml
@@ -0,0 +1,13 @@
+name:
+  title: 'Style name'
+  type: 'item'
+data:
+  title: 'Data'
+  type: 'fieldset'
+  subkeys: '1'
+weight:
+  title: 'Weight'
+  type: 'weight'
+ieid:
+  title: '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..f634bc6
--- /dev/null
+++ b/core/modules/image/meta/image.style.effects.scale.yml
@@ -0,0 +1,9 @@
+data.width:
+  title: 'Width'
+  type: 'number'
+data.height:
+  title: 'Height'
+  type: 'number'
+data.upscale:
+  title: 'Upscale'
+  type: 'checkbox'
diff --git a/core/modules/system/meta/system.maintenance.yml b/core/modules/system/meta/system.maintenance.yml
new file mode 100644
index 0000000..483a361
--- /dev/null
+++ b/core/modules/system/meta/system.maintenance.yml
@@ -0,0 +1,6 @@
+enabled:
+  title: 'Put site into maintenance mode'
+  type: 'boolean'
+message:
+  title: 'Message to display when in maintenance mode'
+  type: 'text'
diff --git a/core/modules/system/meta/system.site.yml b/core/modules/system/meta/system.site.yml
new file mode 100644
index 0000000..ee29ae2
--- /dev/null
+++ b/core/modules/system/meta/system.site.yml
@@ -0,0 +1,18 @@
+name:
+  title: 'Site name'
+  type: 'string'
+mail:
+  title: 'Site mail'
+  type: 'email'
+slogan:
+  title: 'Site slogan'
+  type: 'string'
+page.403:
+  title: 'Default 403 (access denied) page'
+  type: 'path'
+page.404:
+  title: 'Default 404 (not found) page'
+  type: 'path'
+page.front:
+  title: 'Default front page'
+  type: 'path'
