diff --git a/core/includes/config.inc b/core/includes/config.inc
index 8c2772b..feb282b 100644
--- a/core/includes/config.inc
+++ b/core/includes/config.inc
@@ -1,6 +1,14 @@
 <?php
 
 use Drupal\Core\Config\DrupalVerifiedStorageSQL;
+use Drupal\Core\Config\DrupalConfigTree;
+use Drupal\Core\Config\ConfigException;
+
+/**
+ * The value a module should return from hook_config_reload() to indicate that
+ * it should be called again by the config system during this reload.
+ */
+const CONFIG_DEFER_RELOAD = 'CONFIG_DEFER_RELOAD';
 
 /**
  * @file
@@ -26,7 +34,7 @@ function config_get_config_directory() {
 }
 
 /**
- * Moves the default config supplied by a module to the live config directory.
+ * Moves the default config supplied by a module to the active store.
  *
  * @param
  *   The name of the module we are installing.
@@ -119,9 +127,9 @@ function config_get_verified_storage_names_with_prefix($prefix = '') {
  *   The name of the configuration object to retrieve. The name corresponds to
  *   an XML configuration file. For @code config(book.admin) @endcode, the
  *   config object returned will contain the contents of book.admin.xml.
- * @param $class
- *   The class name of the config object to be returned. Defaults to
- *   DrupalConfig.
+ * @param $storage_class
+ *   The class name of the storage driver for the DrupalConfig object to use.
+ *   Defaults to DrupalVerifiedStorageSQL.
  *
  * @return
  *   An instance of the class specified in the $class parameter.
@@ -129,8 +137,11 @@ function config_get_verified_storage_names_with_prefix($prefix = '') {
  * @todo Replace this with an appropriate factory / ability to inject in
  *   alternate storage engines..
  */
-function config($name, $class = 'Drupal\Core\Config\DrupalConfig') {
-  return new $class(new DrupalVerifiedStorageSQL($name));
+function config($name, $storage_class = NULL) {
+  if ($storage_class === NULL) {
+    $storage_class = variable_get('config_default_storage', 'Drupal\Core\Config\DrupalVerifiedStorageSQL');
+  }
+  return new Drupal\Core\Config\DrupalConfig(new $storage_class($name));
 }
 
 /**
@@ -202,7 +213,7 @@ function config_xml_to_array($data) {
  */
 function config_encode($data) {
   // Convert the supplied array into a SimpleXMLElement.
-  $xml_object = new SimpleXMLElement("<?xml version=\"1.0\"?><config></config>");
+  $xml_object = new SimpleXMLElement("<?xml version=\"1.0\"?" . "><config></config>");
   config_array_to_xml($data, $xml_object);
 
   // Pretty print the result.
@@ -240,3 +251,208 @@ function config_array_to_xml($array, &$xml_object) {
     }
   }
 }
+
+/**
+ * Reload config from disc and write new settings to the active store.
+ */
+function config_reload() {
+  $config_changes = config_get_changes_from_disc();
+  if (empty($config_changes)) {
+    return;
+  }
+
+  $lock_attempts = 0;
+  $lock_acquired = FALSE;
+  do {
+    if (!$lock_acquired = lock_acquire(__FUNCTION__, 5)) {
+      lock_wait(__FUNCTION__, 5);
+      continue;
+    }
+
+    try {
+      config_invoke_reload_hooks($config_changes);
+      config_reload_save_changes($config_changes);
+    }
+    catch (ConfigException $e) {
+      watchdog_exception('config_reload', $e);
+      config_invoke_reload_error_hooks($config_changes);
+      lock_release(__FUNCTION__);
+      return;
+    }
+  } while ($lock_acquired === FALSE && ++$lock_attempts < 5);
+
+  if ($lock_acquired) {
+    lock_release(__FUNCTION__);
+    return TRUE;
+  }
+  else {
+    watchdog('config_reload', 'Failed to get lock while trying to reload config.');
+    return FALSE;
+  }
+}
+
+/**
+ * Writes an array of config file changes to the active store.
+ *
+ * @param $config_changes
+ *   An array of changes to be written.
+ */
+function config_reload_save_changes($config_changes) {
+  foreach (array('new', 'changed', 'deleted') as $type) {
+    foreach ($config_changes[$type] as $name) {
+      if ($type == 'deleted') {
+        config($name)->delete();
+      }
+      else {
+        // Get the active store object, set the new data from file, then
+        // save, which will also update the .sig file.
+        $active_store_config = config($name);
+        $active_store_config->setData(config($name, 'Drupal\Core\Config\DrupalConfigFile')->get());
+        $active_store_config->save();
+      }
+    }
+  }
+}
+
+/**
+ * Invokes hook_config_reload_validate() and hook_config_reload() implementations.
+ *
+ * @param $config_changes
+ *   An array of changes to be loaded.
+ */
+function config_invoke_reload_hooks($config_changes) {
+  $active_config_tree = config_tree();
+  $file_config_tree = config_tree('Drupal\Core\Config\DrupalConfigFile');
+
+  foreach (config_sort_module_reload_dependencies(module_implements('config_reload_validate')) as $module) {
+    $function = $module . '_config_reload_validate';
+    $function($config_changes, $active_config_tree, $file_config_tree);
+  }
+
+  // We allow modules to signal that they would like to be rerun after all
+  // other modules by returning CONFIG_DEFER_RELOAD. Loop until there are no
+  // modules left that indicate they would like to be rerun, checking that we're
+  // not stuck rerunning the same list of modules over and over at each cycle.
+  $modules = config_sort_module_reload_dependencies(module_implements('config_reload'));
+  do {
+    $initial_module_list = $modules;
+    $modules = array();
+    foreach ($initial_module_list as $module) {
+      $function = $module . '_config_reload';
+      if ($function($config_changes, $file_config_tree, $active_config_tree) === CONFIG_DEFER_RELOAD) {
+        $modules[] = $module;
+      }
+    }
+  } while ($modules && $modules != $initial_module_list);
+
+  // If there are modules left that haven't run their reload hook, then we hit
+  // an infinite loop.
+  if ($modules) {
+    throw new ConfigException("Dependency loop detected while reloading configuration from disc:");
+  }
+}
+
+/**
+ * Invokes hook_config_reload_error() implementations.
+ *
+ * During a reload run, modules may make changes that cannot be rolled back.
+ * This hook allows modules to react to an error that occurs after they have
+ * made such changes, and make sure that the state of configuration in the
+ * active store is correct.
+ *
+ * @param $config_changes
+ *   An array of changes to be loaded.
+ */
+function config_invoke_reload_error_hooks($config_changes) {
+  $active_config_tree = config_tree();
+  $file_config_tree = config_tree('Drupal\Core\Config\DrupalConfigFile');
+
+  $modules = config_sort_module_reload_dependencies(module_implements('config_reload_error'));
+  foreach ($modules as $module) {
+    $function = $module . '_config_reload_error';
+    try {
+      $function($config_changes, $active_config_tree, $file_config_tree);
+    }
+    catch (ConfigException $e) {
+      // Just keep going, because we need to allow all modules to react even if
+      // some of them are behaving badly.
+    }
+  }
+}
+
+/**
+ * Load all the config names! From disc.
+ */
+function config_get_names_from_disc() {
+  $config_names = array();
+  foreach (glob(config_get_config_directory() . '/' . '*.xml') as $key => $file) {
+    $parts = explode('/', $file);
+    $file = array_pop($parts);
+    $name = str_replace('.xml', '', $file);
+    $config_names[] = $name;
+  }
+  return $config_names;
+}
+
+/**
+ * Returns a DrupalConfigTree object with the given storage backend.
+ *
+ * @param $storage_class
+ *   A storage class.
+ * @return
+ *   A DrupalConfigTree object.
+ */
+function config_tree($storage_class = NULL) {
+  if ($storage_class === NULL) {
+    $storage_class = variable_get('config_default_storage', 'Drupal\Core\Config\DrupalVerifiedStorageSQL');
+  }
+  return new DrupalConfigTree($storage_class);
+}
+
+/**
+ * Sort the given list of modules based on dependency.
+ *
+ * @param $modules
+ *   A list of modules.
+ * @return
+ *   The list of modules sorted by dependency.
+ */
+function config_sort_module_reload_dependencies($modules) {
+  // Get all module data so we can find find weights and sort.
+  $module_data = system_rebuild_module_data();
+
+  $sorted_modules = array();
+  foreach ($modules as $module) {
+    $sorted_modules[$module] = $module_data[$module]->sort;
+  }
+  arsort($sorted_modules);
+  return array_keys($sorted_modules);
+}
+
+/**
+ * Returns a list of changes on disc compared to the active store.
+ *
+ * @return
+ *   The list of files changed on disc compared to the active store.
+ */
+function config_get_changes_from_disc() {
+  $disc_config_names = config_get_names_from_disc();
+  $active_config_names = config_get_verified_storage_names_with_prefix();
+  $config_changes = array(
+    'new' => array_diff($disc_config_names, $active_config_names),
+    'changed' => array(),
+    'deleted' => array_diff($active_config_names, $disc_config_names),
+  );
+  foreach (array_intersect($disc_config_names, $active_config_names) as $name) {
+    $active_config = config($name);
+    $file_config = config($name, 'Drupal\Core\Config\DrupalConfigFile');
+    if ($active_config->get() != $file_config->get()) {
+      $config_changes['changed'][] = $name;
+    }
+  }
+  if (empty($config_changes['new']) && empty($config_changes['changed']) && empty($config_changes['deleted'])) {
+    return FALSE;
+  }
+  return $config_changes;
+}
+
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 07e25a0..941b667 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1035,7 +1035,7 @@ function install_settings_form_submit($form, &$form_state) {
   $config_path = conf_path() . '/files/' . $settings['config_directory_name']['value'];
   if (!file_prepare_directory($config_path, FILE_CREATE_DIRECTORY)) {
     // How best to handle errors here?
-  };
+  }
 
   // Write out a .htaccess file that will protect the config directory from
   // prying eyes.
diff --git a/core/includes/module.inc b/core/includes/module.inc
index df9c138..37e6e23 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -463,7 +463,7 @@ function module_enable($module_list, $enable_dependencies = TRUE) {
         $versions = drupal_get_schema_versions($module);
         $version = $versions ? max($versions) : SCHEMA_INSTALLED;
 
-        // Copy any default configuration data to the system config directory/
+        // Copy any default configuration data to the active store.
         config_install_default_config($module);
 
         // If the module has no current updates, but has some that were
diff --git a/core/lib/Drupal/Core/Config/DrupalConfig.php b/core/lib/Drupal/Core/Config/DrupalConfig.php
index 54397e7..6207daa 100644
--- a/core/lib/Drupal/Core/Config/DrupalConfig.php
+++ b/core/lib/Drupal/Core/Config/DrupalConfig.php
@@ -97,6 +97,10 @@ class DrupalConfig {
     }
   }
 
+  public function setData(array $data) {
+    $this->data = $data;
+  }
+
   /**
    * Sets value in this config object.
    *
diff --git a/core/lib/Drupal/Core/Config/DrupalConfigFile.php b/core/lib/Drupal/Core/Config/DrupalConfigFile.php
new file mode 100644
index 0000000..763ee7d
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/DrupalConfigFile.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace Drupal\Core\Config;
+
+use Drupal\Core\Config\DrupalConfigVerifiedStorageInterface;
+
+/**
+ * Represents a config file.
+ */
+class DrupalConfigFile implements DrupalConfigVerifiedStorageInterface {
+
+  /**
+   * Constructs a DrupalConfigFile object.
+   *
+   * @param string $name
+   *   The name for the configuration data. Should be lowercase.
+   */
+  public function __construct($name) {
+    $this->name = $name;
+  }
+
+  /**
+   * Checks whether the XML configuration file already exists on disk.
+   *
+   * @return
+   *   Boolean based on file's existence.
+   */
+  protected function exists() {
+    return file_exists($this->getFilePath());
+  }
+
+  /**
+   * Returns the path to the XML configuration file.
+   *
+   * @return
+   *   @todo
+   */
+  public function getFilePath() {
+    return config_get_config_directory() . '/' . $this->name  . '.xml';
+  }
+
+  /**
+   * Writes the contents of the configuration file to disk.
+   *
+   * @param $data
+   *   The data to be written to the file.
+   *
+   * @throws
+   *   Exception
+   */
+  public function write($data) {
+    if (!file_put_contents($this->getFilePath(), $data)) {
+      throw new \Exception('Failed to write configuration file: ' . $this->getFilePath());
+    }
+  }
+
+  /**
+   * Returns the contents of the configuration file.
+   *
+   * @return
+   *   @todo
+   */
+  public function read() {
+    if ($this->exists()) {
+      return file_get_contents($this->getFilePath());
+    }
+    throw new \Exception('Failed to read configuration file: ' . $this->getFilePath());
+  }
+
+  /**
+   * Deletes a configuration file.
+   */
+  public function delete() {
+    return @drupal_unlink($this->getFilePath());
+  }
+
+  /**
+   * Copies the configuration data from the verified storage into a file.
+   */
+  public function copyToFile() {
+    // TODO: no-op to keep the interface happy.
+  }
+
+  /**
+   * Copies the configuration data from the file into the verified storage.
+   */
+  public function copyFromFile() {
+    // TODO: no-op to keep the interface happy.
+  }
+
+  /**
+   * Deletes the configuration data file.
+   */
+  public function deleteFile() {
+    return $this->delete();
+  }
+
+  /**
+   * Checks whether the file and the verified storage is in sync.
+   *
+   * @return
+   *   TRUE if the file and the verified storage contains the same data, FALSE
+   *   if not.
+   */
+  public function isOutOfSync() {
+    return FALSE;
+  }
+
+  /**
+   * Writes the configuration data into the active storage but not the file.
+   *
+   * @param $data
+   *   The configuration data to write into active storage.
+   */
+  public function writeToActive($data) {
+    // TODO: no-op to keep the interface happy.
+  }
+
+  /**
+   * Writes the configuration data into the file.
+   *
+   * @param $data
+   *   The configuration data to write into the file.
+   */
+  public function writeToFile($data) {
+    return $this->write($data);
+  }
+
+  /**
+   * Gets names starting with this prefix.
+   *
+   * @param $prefix
+   *   The prefix of the files we are searching for.
+   *
+   * @return
+   *   An array of file names under a branch.
+   *
+   * @see config_get_signed_file_storage_names_with_prefix()
+   */
+  public static function getNamesWithPrefix($prefix) {
+    return config_get_signed_file_storage_names_with_prefix($prefix);
+  }
+}
+
diff --git a/core/lib/Drupal/Core/Config/DrupalConfigTree.php b/core/lib/Drupal/Core/Config/DrupalConfigTree.php
new file mode 100644
index 0000000..0d551ac
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/DrupalConfigTree.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Drupal\Core\Config;
+
+class DrupalConfigTree {
+
+  protected $storage_class;
+
+  public function __construct($storage_class) {
+    $this->storage_class = $storage_class;
+  }
+
+  public function get($name) {
+    return config($name, $this->storage_class);
+  }
+
+}
+
diff --git a/core/modules/config/config.admin.inc b/core/modules/config/config.admin.inc
new file mode 100644
index 0000000..a0a0a0b
--- /dev/null
+++ b/core/modules/config/config.admin.inc
@@ -0,0 +1,58 @@
+<?php
+
+/**
+ * @file
+ * Admin page callbacks for the config module.
+ */
+
+/**
+ * Reload config from disc form.
+ */
+function config_admin_config_reload_form($form, &$form_state) {
+  if ($config_changes = config_get_changes_from_disc()) {
+    foreach ($config_changes as $config_change_type => $config_files) {
+      if (count($config_files) == 0) {
+        continue;
+      }
+
+      $form[$config_change_type] = array(
+        '#type' => 'fieldset',
+        '#title' => $config_change_type . '(' . count($config_files) . ')',
+        '#collapsible' => TRUE,
+      );
+
+      $rows = array();
+      foreach ($config_files as $config_file) {
+        $rows[] = array('data' => array($config_file));
+      }
+
+      $form[$config_change_type]['config_files'] = array(
+        '#markup' => theme('table', array('header' => array('filename'), 'rows' => $rows)),
+      );
+    }
+
+    $form['reload'] = array(
+      '#type' => 'submit',
+      '#value' => 'Reload config from disc',
+    );
+  }
+  else {
+    $form['no_changes'] = array(
+      '#markup' => 'There are no changes on disc to reload.'
+    );
+  }
+  return $form;
+}
+
+/**
+ * Reload config from disc form submit handler.
+ */
+function config_admin_config_reload_form_submit($form, &$form_state) {
+  if (config_reload()) {
+    drupal_set_message('Configuration successfully reloaded from disc.');
+  }
+  else {
+    drupal_set_message('There was an error reloading configuration from disc.', 'error');
+  }
+}
+
diff --git a/core/modules/config/config.api.php b/core/modules/config/config.api.php
new file mode 100644
index 0000000..0f05b84
--- /dev/null
+++ b/core/modules/config/config.api.php
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * @file
+ * Hooks provided by the Config module.
+ */
+
+/**
+ * @defgroup config_hooks Configuration system hooks
+ * @{
+ * TODO: overall description of the configuration system.
+ * @}
+ */
+
+/**
+ * Reload config changes from disk.
+ */
+function hook_config_reload($config_changes, $active_config_tree, $file_config_tree) {
+  // TODO: working example.
+}
+
+/**
+ * Validate configuration changes before they are saved to the active store.
+ */
+function hook_config_reload_validate($config_changes, $active_config_tree, $file_config_tree) {
+  // TODO: working example.
+}
+
+/**
+ * Validate configuration changes before they are saved to the active store.
+ */
+function hook_config_reload_error($config_changes, $active_config_tree, $file_config_tree) {
+  // TODO: working example.
+}
+
diff --git a/core/modules/config/config.module b/core/modules/config/config.module
index b3d9bbc..abc641c 100644
--- a/core/modules/config/config.module
+++ b/core/modules/config/config.module
@@ -1 +1,24 @@
 <?php
+
+/**
+ * @file
+ * Configuration system that lets administrators modify
+ * configuration of the site.
+ */
+
+/**
+ * Implements hook_menu().
+ */
+function config_menu() {
+  $items['admin/config/development/reload'] = array(
+    'title' => 'Configuration reload',
+    'description' => 'Reload configuration from disc.',
+    'weight' => -25,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('config_admin_config_reload_form'),
+    'access arguments' => array('reload configuration from disc'),
+    'file' => 'config.admin.inc',
+  );
+  return $items;
+}
+
diff --git a/core/modules/config/config.test b/core/modules/config/config.test
index 395a3a9..5db0678 100644
--- a/core/modules/config/config.test
+++ b/core/modules/config/config.test
@@ -268,3 +268,124 @@ class ConfigFileContentTestCase extends DrupalWebTestCase {
     // Attempt to delete non-existing configuration.
   }
 }
+
+/**
+ * Tests config_reload() functionality.
+ */
+class ConfigReloadTestCase extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Reload configuration',
+      'description' => 'Tests reloading configuration files and saving to the active store.',
+      'group' => 'Configuration',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp('config_test');
+  }
+
+  public function testDeletedConfigFile() {
+    // Check a value in the active store for config_test.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'bar', 'The config_test.system.xml file has been loaded into the active store.');
+    // Delete one of the config_test files.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Run config_reload().
+    config_reload();
+    // Check that the value has disappeared.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') === NULL, 'The config_test.system.xml file values has been removed from the active store.');
+  }
+
+  public function testNewConfigFile() {
+    // Create a new file.
+    $xml =<<<XML
+<?xml version="1.0"?>
+<config>
+  <add_me>new value</add_me>
+</config>
+XML;
+    $new_config_file_path = config_get_config_directory() . '/config_test.new.xml';
+    file_put_contents($new_config_file_path, $xml);
+    // Run config_reload().
+    config_reload();
+    // Check that the value has appeared.
+    $config = config('config_test.new');
+    $this->assertTrue($config->get('add_me') == 'new value', 'A new config file was loaded into the active store by config_reload().');
+  }
+
+  public function testUpdatedConfigFile() {
+    // Update a config_test config file in-place, check that the value does not
+    // appear in the active store.
+    $xml =<<<XML
+<?xml version="1.0"?>
+<config>
+  <foo>not bar</foo>
+</config>
+XML;
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    file_put_contents($config_file_path, $xml);
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'bar', 'The config_test.system:foo value has not changed.');
+    // Run config_reload().
+    config_reload();
+    // Check that the updated value has appeared.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'not bar', 'The config_test.system:foo value has been updated by the config_reload() run.');
+  }
+
+  public function testReloadHook() {
+    // Delete a file so that hook_config_reload() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Run config_reload().
+    config_reload();
+    // Check that we get called when config_reload() is run.
+    $config_reload_hook_called = isset($GLOBALS['hook_config_reload']) && $GLOBALS['hook_config_reload'] == 'config_test_config_reload';
+    $this->assertTrue($config_reload_hook_called, "The config_test module's hook_config_reload() implementation was called.");
+  }
+
+  public function testReloadErrorHook() {
+    // Delete a file so that hook_config_reload() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Enable the module that will blow up during a config_reload() or set a
+    // global or something.
+    $GLOBALS['config_reload_throw_error'] = TRUE;
+    // Run config_reload().
+    config_reload();
+    // Check that we get called when config_reload() is run and the explosion
+    // happens.
+    $config_reload_error_hook_called = isset($GLOBALS['hook_config_reload_error']) && $GLOBALS['hook_config_reload_error'] == 'config_test_config_reload_error';
+    $this->assertTrue($config_reload_error_hook_called, "The config_test module's hook_config_reload_error() implementation was called.");
+  }
+
+  public function testReloadValidateHook() {
+    // Delete a file so that hook_config_reload() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Run config_reload().
+    config_reload();
+    // Check that we get called when config_reload() is run.
+    $config_reload_validate_hook_called = isset($GLOBALS['hook_config_reload_validate']) && $GLOBALS['hook_config_reload_validate'] == 'config_test_config_reload_validate';
+    $this->assertTrue($config_reload_validate_hook_called, "The config_test module's hook_config_reload_validate() implementation was called.");
+  }
+
+  public function testReloadValidateHookThrowsError() {
+    // Delete a file so that hook_config_reload() hooks are run.
+    $config_file_path = config_get_config_directory() . '/config_test.system.xml';
+    unlink($config_file_path);
+    // Enable the module that will blow up during a hook_config_reload_validate() or set a
+    // global or something.
+    $GLOBALS['config_reload_validate_throw_error'] = TRUE;
+    // Run config_reload().
+    config_reload();
+    // Check that the config reload run didn't update the active store.
+    $config = config('config_test.system');
+    $this->assertTrue($config->get('foo') == 'bar', 'The config_test.system:foo value has not changed.');
+  }
+}
+
diff --git a/core/modules/config/config_test/config/config_test.delete.xml b/core/modules/config/config_test/config/config_test.delete.xml
new file mode 100644
index 0000000..4ec808f
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.delete.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<config>
+  <delete_me>bar</delete_me>
+</config>
diff --git a/core/modules/config/config_test/config/config_test.system.xml b/core/modules/config/config_test/config/config_test.system.xml
new file mode 100644
index 0000000..6ea745f
--- /dev/null
+++ b/core/modules/config/config_test/config/config_test.system.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<config>
+  <foo>bar</foo>
+</config>
diff --git a/core/modules/config/config_test/config_test.info b/core/modules/config/config_test/config_test.info
new file mode 100644
index 0000000..8735450
--- /dev/null
+++ b/core/modules/config/config_test/config_test.info
@@ -0,0 +1,6 @@
+name = Configuration test module
+package = Core
+version = VERSION
+core = 8.x
+dependencies[] = config
+hidden = TRUE
diff --git a/core/modules/config/config_test/config_test.module b/core/modules/config/config_test/config_test.module
new file mode 100644
index 0000000..f14fd93
--- /dev/null
+++ b/core/modules/config/config_test/config_test.module
@@ -0,0 +1,36 @@
+<?php
+
+use Drupal\Core\Config\ConfigException;
+
+/**
+ * Implements hook_config_reload().
+ */
+function config_test_config_reload($config_changes, $active_config_tree, $file_config_tree) {
+  if (!empty($GLOBALS['config_reload_throw_error'])) {
+    throw new ConfigException("ZOMG I'm really bad at this game.");
+  }
+
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_reload'] = __FUNCTION__;
+}
+
+/**
+ * Implements hook_config_reload_error().
+ */
+function config_test_config_reload_error($config_changes, $active_config_tree, $file_config_tree) {
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_reload_error'] = __FUNCTION__;
+}
+
+/**
+ * Implements hook_config_reload_validate().
+ */
+function config_test_config_reload_validate($config_changes, $active_config_tree, $file_config_tree) {
+  if (!empty($GLOBALS['config_reload_validate_throw_error'])) {
+    throw new ConfigException("ZOMG these changes look wrong.");
+  }
+
+  // Set a global value we can check in test code.
+  $GLOBALS['hook_config_reload_validate'] = __FUNCTION__;
+}
+
diff --git a/core/modules/image/image.module b/core/modules/image/image.module
index b3d0dda..8adcb9c 100644
--- a/core/modules/image/image.module
+++ b/core/modules/image/image.module
@@ -527,6 +527,36 @@ function image_style_save($style) {
 }
 
 /**
+ * Implements hook_config_reload().
+ */
+function image_config_reload($config_changes, $files_config_tree, $active_config_tree) {
+  foreach ($config_changes['new'] as $file_name) {
+    if (strpos($file_name, 'image.styles.') === 0) {
+      $style = $files_config_tree->get($file_name)->get();
+      $style['is_new'] = TRUE;
+      module_invoke_all('image_style_save', $style);
+      image_style_flush($style);
+    }
+  }
+  foreach ($config_changes['changed'] as $file_name) {
+    if (strpos($file_name, 'image.styles.') === 0) {
+      $style = $files_config_tree->get($file_name)->get();
+      $style['is_new'] = FALSE;
+      module_invoke_all('image_style_save', $style);
+      image_style_flush($style);
+    }
+  }
+  foreach ($config_changes['deleted'] as $file_name) {
+    if (strpos($file_name, 'image.styles.') === 0) {
+      image_style_flush($style);
+      $style['old_name'] = $style['name'];
+      $style['name'] = '';
+      module_invoke_all('image_style_delete', $style);
+    }
+  }
+}
+
+/**
  * Delete an image style.
  *
  * @param $style
diff --git a/core/modules/image/image.test b/core/modules/image/image.test
index 2c422a7..4d643c8 100644
--- a/core/modules/image/image.test
+++ b/core/modules/image/image.test
@@ -5,6 +5,11 @@
  * Tests for image.module.
  */
 
+use Drupal\Core\Config\SignedFileStorage;
+use Drupal\Core\Config\DrupalConfigVerifiedStorageInterface;
+use Drupal\Core\Config\ConfigException;
+
+
 /**
  * TODO: Test the following functions.
  *
@@ -1241,3 +1246,29 @@ class ImageDimensionsScaleTestCase extends DrupalUnitTestCase {
     }
   }
 }
+
+
+/**
+ * Tests the configuration management system for images.
+ */
+class ImageConfigTest extends DrupalWebTestCase {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Image configuration',
+      'description' => 'Tests reading and writing of image configuration files.',
+      'group' => 'Image',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp(array('image', 'image_test'));
+  }
+
+  function testImageConfiguration() {
+    $this->assertTrue(module_exists('image_test'), t('Image test module enabled.'));
+    $config = config('image_test.style.test');
+    debug($config);
+  }
+
+}
diff --git a/core/modules/image/tests/config/image_test.style.test.xml b/core/modules/image/tests/config/image_test.style.test.xml
new file mode 100644
index 0000000..f57f895
--- /dev/null
+++ b/core/modules/image/tests/config/image_test.style.test.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<config>
+  <name>test</name>
+  <effects>
+    <image_scale_640_640_1>
+      <name>image_scale</name>
+      <ieid>image_scale_640_640_1</ieid>
+      <data>
+        <width>640</width>
+        <height>640</height>
+        <upscale>1</upscale>
+      </data>
+      <weight>0</weight>
+    </image_scale_640_640_1>
+  </effects>
+</config>
diff --git a/core/modules/image/tests/image_module_test.info b/core/modules/image/tests/image_module_test.info
index 01d4d71..e28c11a 100644
--- a/core/modules/image/tests/image_module_test.info
+++ b/core/modules/image/tests/image_module_test.info
@@ -3,5 +3,6 @@ description = Provides hook implementations for testing Image module functionali
 package = Core
 version = VERSION
 core = 8.x
+dependencies[] = image
 files[] = image_module_test.module
 hidden = TRUE
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 978b0f4..1594d12 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -3203,3 +3203,4 @@ function system_actions_remove_orphans() {
   actions_synchronize(TRUE);
   drupal_goto('admin/config/system/actions/manage');
 }
+
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index fd571ce..4b73d51 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -745,6 +745,18 @@ function system_menu() {
     'file' => 'system.admin.inc',
   );
 
+  // Config system reload.
+  $items['admin/config/config/reload'] = array(
+    'title' => 'Configuration reload',
+    'description' => 'Reload configuration from disc.',
+    'position' => 'left',
+    'weight' => -10,
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('system_admin_config_reload_form'),
+    'access arguments' => array('reload configuration from disc'),
+    'file' => 'system.admin.inc',
+  );
+
   // Media settings.
   $items['admin/config/media'] = array(
     'title' => 'Media',
