From 73069e05e8a32f421e0f9a3132ae76d94f3bdcde Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Fri, 16 Jan 2015 10:43:35 +0000
Subject: [PATCH] Issue #2392319 by alexpott, effulgentsia: Config objects (but
 not config entities) should by default be immutable

---
 core/includes/file.inc                        |  5 +-
 core/includes/install.core.inc                |  2 +-
 core/includes/install.inc                     |  2 +-
 core/includes/module.inc                      |  3 +-
 core/lib/Drupal.php                           |  4 +-
 core/lib/Drupal/Core/Config/Config.php        |  3 +-
 core/lib/Drupal/Core/Config/ConfigFactory.php | 85 ++++++++++++++++---
 .../Core/Config/ConfigFactoryInterface.php    | 37 ++++++--
 core/lib/Drupal/Core/Config/ConfigManager.php |  2 +-
 .../Config/Entity/ConfigEntityStorage.php     | 10 +--
 .../Drupal/Core/Config/ImmutableConfig.php    | 61 +++++++++++++
 .../Core/Config/ImmutableConfigException.php  | 16 ++++
 .../Drupal/Core/Extension/ModuleInstaller.php |  8 +-
 .../Drupal/Core/Extension/ThemeHandler.php    |  8 +-
 core/lib/Drupal/Core/Form/ConfigFormBase.php  | 17 +---
 .../Drupal/Core/Form/ConfigFormBaseTrait.php  | 77 +++++++++++++++++
 core/lib/Drupal/Core/Form/FormBase.php        |  2 +-
 .../Core/Installer/Form/SiteConfigureForm.php | 11 +++
 .../Core/Menu/StaticMenuLinkOverrides.php     |  7 +-
 .../aggregator/src/Form/SettingsForm.php      |  7 ++
 .../aggregator/processor/DefaultProcessor.php | 21 +++--
 .../aggregator/processor/TestProcessor.php    | 13 ++-
 core/modules/book/book.module                 |  2 +-
 .../book/src/Form/BookSettingsForm.php        |  7 ++
 .../ckeditor/src/Tests/CKEditorTest.php       |  2 +-
 core/modules/color/color.module               | 22 +++--
 .../src/Form/ConfigSingleImportForm.php       |  2 +-
 .../config/src/Tests/ConfigCRUDTest.php       |  4 +-
 .../config/src/Tests/ConfigEventsTest.php     |  7 +-
 .../src/Tests/ConfigLanguageOverrideTest.php  |  7 +-
 .../src/Tests/ConfigModuleOverridesTest.php   |  2 +-
 .../config/src/Tests/ConfigOverrideTest.php   | 24 ++++--
 .../src/Tests/ConfigOverridesPriorityTest.php |  2 +-
 .../src/SchemaListenerController.php          | 23 ++++-
 .../src/Tests/ConfigTranslationUiTest.php     |  2 +-
 core/modules/contact/contact.module           |  6 +-
 .../contact/src/ContactFormEditForm.php       | 11 +++
 core/modules/dblog/dblog.module               |  4 +-
 core/modules/forum/src/ForumSettingsForm.php  |  7 ++
 core/modules/language/language.module         | 10 ++-
 .../src/ConfigurableLanguageInterface.php     | 11 +++
 .../src/ConfigurableLanguageManager.php       | 30 +++----
 .../src/Entity/ConfigurableLanguage.php       | 10 ++-
 .../src/Form/NegotiationBrowserDeleteForm.php | 10 +++
 .../src/Form/NegotiationBrowserForm.php       |  7 ++
 .../src/Form/NegotiationConfigureForm.php     |  7 ++
 .../src/Form/NegotiationSelectedForm.php      |  7 ++
 .../src/Form/NegotiationSessionForm.php       |  7 ++
 .../language/src/Form/NegotiationUrlForm.php  |  7 ++
 .../language/src/LanguageNegotiator.php       |  2 +-
 .../tests/language_test/language_test.module  |  5 +-
 core/modules/locale/locale.install            |  2 +-
 core/modules/locale/locale.module             |  4 +-
 .../locale/src/Form/LocaleSettingsForm.php    |  7 ++
 .../locale/src/Tests/LocaleUpdateBase.php     |  8 +-
 .../src/Plugin/migrate/destination/Config.php | 11 +--
 .../tests/src/Unit/destination/ConfigTest.php |  7 +-
 core/modules/node/node.module                 |  4 +-
 .../search/src/SearchPageListBuilder.php      |  2 +-
 .../search/src/SearchPageRepository.php       |  4 +-
 .../src/Unit/SearchPageRepositoryTest.php     |  4 +-
 core/modules/shortcut/shortcut.install        |  4 +-
 core/modules/shortcut/shortcut.module         |  2 +-
 .../src/Form/SimpletestSettingsForm.php       |  7 ++
 .../simpletest/src/InstallerTestBase.php      |  2 +-
 .../modules/simpletest/src/KernelTestBase.php |  7 +-
 core/modules/simpletest/src/TestBase.php      |  2 +-
 core/modules/simpletest/src/WebTestBase.php   |  8 +-
 .../statistics/src/StatisticsSettingsForm.php |  7 ++
 core/modules/syslog/syslog.install            |  2 +-
 core/modules/syslog/syslog.module             |  4 +-
 .../system/src/Controller/ThemeController.php | 11 ++-
 core/modules/system/src/Form/CronForm.php     |  7 ++
 .../system/src/Form/FileSystemForm.php        |  7 ++
 .../system/src/Form/ImageToolkitForm.php      |  7 ++
 core/modules/system/src/Form/LoggingForm.php  |  7 ++
 .../system/src/Form/PerformanceForm.php       |  7 ++
 core/modules/system/src/Form/RegionalForm.php |  7 ++
 core/modules/system/src/Form/RssFeedsForm.php |  7 ++
 .../system/src/Form/SiteInformationForm.php   |  7 ++
 .../src/Form/SiteMaintenanceModeForm.php      |  7 ++
 .../system/src/Form/ThemeAdminForm.php        |  7 ++
 .../system/src/Form/ThemeSettingsForm.php     | 22 ++++-
 .../src/Plugin/ImageToolkit/GDToolkit.php     |  4 +-
 .../system/src/Tests/Form/FormObjectTest.php  |  2 +-
 core/modules/system/system.install            |  2 +-
 .../modules/form_test/form_test.services.yml  |  1 +
 .../form_test/src/FormTestArgumentsObject.php | 11 ++-
 .../src/FormTestControllerObject.php          | 15 +++-
 .../modules/form_test/src/FormTestObject.php  | 11 ++-
 .../form_test/src/FormTestServiceObject.php   | 13 ++-
 .../src/SystemConfigFormTestForm.php          |  7 ++
 .../src/Plugin/ImageToolkit/TestToolkit.php   |  4 +-
 .../modules/update/src/UpdateSettingsForm.php |  7 ++
 core/modules/user/src/AccountSettingsForm.php | 11 +++
 core/modules/user/user.module                 |  2 +-
 .../views_test_data/views_test_data.install   |  2 +-
 .../src/Form/AdvancedSettingsForm.php         |  7 ++
 .../views_ui/src/Form/BasicSettingsForm.php   |  7 ++
 core/profiles/minimal/minimal.install         |  4 +-
 core/profiles/standard/standard.install       |  6 +-
 .../Config/Entity/ConfigEntityStorageTest.php | 24 +++++-
 .../Tests/Core/Config/ImmutableConfigTest.php | 70 +++++++++++++++
 .../Core/Form/ConfigFormBaseTraitTest.php     | 76 +++++++++++++++++
 .../Core/Menu/StaticMenuLinkOverridesTest.php |  4 +-
 core/tests/Drupal/Tests/UnitTestCase.php      | 25 ++++--
 sites/default/default.settings.php            | 13 ++-
 107 files changed, 976 insertions(+), 201 deletions(-)
 create mode 100644 core/lib/Drupal/Core/Config/ImmutableConfig.php
 create mode 100644 core/lib/Drupal/Core/Config/ImmutableConfigException.php
 create mode 100644 core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php
 create mode 100644 core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php
 create mode 100644 core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php

diff --git a/core/includes/file.inc b/core/includes/file.inc
index effb71c03d06..d47fbc44f054 100644
--- a/core/includes/file.inc
+++ b/core/includes/file.inc
@@ -1520,9 +1520,10 @@ function drupal_tempnam($directory, $prefix) {
  *   A string containing the path to the temporary directory.
  */
 function file_directory_temp() {
-  $config = \Drupal::config('system.file');
-  $temporary_directory = $config->get('path.temporary');
+  $temporary_directory = \Drupal::config('system.file')->get('path.temporary');
   if (empty($temporary_directory)) {
+    // Needs set up.
+    $config = \Drupal::configFactory()->getEditable('system.file');
     $temporary_directory = file_directory_os_temp();
 
     if (empty($temporary_directory)) {
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 1ec434db09e6..d3d7a04cf4de 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1647,7 +1647,7 @@ function install_download_additional_translations_operations(&$install_state) {
   // If a non-English language was selected, change the default language and
   // remove English.
   if ($langcode != 'en') {
-    \Drupal::config('system.site')->set('langcode', $langcode)->save();
+    \Drupal::configFactory()->getEditable('system.site')->set('langcode', $langcode)->save();
     \Drupal::service('language.default')->set($language);
     if (empty($install_state['profile_info']['keep_english'])) {
       entity_delete_multiple('configurable_language', array('en'));
diff --git a/core/includes/install.inc b/core/includes/install.inc
index ad911db7ef72..e247378750d1 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -618,7 +618,7 @@ function drupal_install_system($install_state) {
 
   // Ensure default language is saved.
   if (isset($install_state['parameters']['langcode'])) {
-    \Drupal::config('system.site')
+    \Drupal::configFactory()->getEditable('system.site')
       ->set('langcode', $install_state['parameters']['langcode'])
       ->save();
   }
diff --git a/core/includes/module.inc b/core/includes/module.inc
index 1ac014a1e2a5..f4fac6e85b2a 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -211,8 +211,7 @@ function drupal_required_modules() {
  *   An integer representing the weight of the module.
  */
 function module_set_weight($module, $weight) {
-  // Update the module weight in the config file that contains it.
-  $extension_config = \Drupal::config('core.extension');
+  $extension_config = \Drupal::configFactory()->getEditable('core.extension');
   if ($extension_config->get("module.$module") !== NULL) {
     $extension_config
       ->set("module.$module", $weight)
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
index 8e31869b5227..7b52d13181d3 100644
--- a/core/lib/Drupal.php
+++ b/core/lib/Drupal.php
@@ -298,8 +298,8 @@ public static function lock() {
    *   a configuration file. For @code \Drupal::config('book.admin') @endcode, the config
    *   object returned will contain the contents of book.admin configuration file.
    *
-   * @return \Drupal\Core\Config\Config
-   *   A configuration object.
+   * @return \Drupal\Core\Config\ImmutableConfig
+   *   An immutable configuration object.
    */
   public static function config($name) {
     return static::$container->get('config.factory')->get($name);
diff --git a/core/lib/Drupal/Core/Config/Config.php b/core/lib/Drupal/Core/Config/Config.php
index ed9c28efb376..51ade6ce736f 100644
--- a/core/lib/Drupal/Core/Config/Config.php
+++ b/core/lib/Drupal/Core/Config/Config.php
@@ -79,8 +79,7 @@ public function __construct($name, StorageInterface $storage, EventDispatcherInt
    */
   public function initWithData(array $data) {
     parent::initWithData($data);
-    $this->settingsOverrides = array();
-    $this->moduleOverrides = array();
+    $this->resetOverriddenData();
     return $this;
   }
 
diff --git a/core/lib/Drupal/Core/Config/ConfigFactory.php b/core/lib/Drupal/Core/Config/ConfigFactory.php
index ce092d374ad3..46aaeada3218 100644
--- a/core/lib/Drupal/Core/Config/ConfigFactory.php
+++ b/core/lib/Drupal/Core/Config/ConfigFactory.php
@@ -102,18 +102,44 @@ public function getOverrideState() {
     return $this->useOverrides;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getEditable($name) {
+    $old_state = $this->getOverrideState();
+    $this->setOverrideState(FALSE);
+    $config = $this->doGet($name, FALSE);
+    $this->setOverrideState($old_state);
+    return $config;
+  }
+
   /**
    * {@inheritdoc}
    */
   public function get($name) {
-    if ($config = $this->loadMultiple(array($name))) {
+    return $this->doGet($name);
+  }
+
+  /**
+   * Returns a configuration object for a given name.
+   *
+   * @param string $name
+   *   The name of the configuration object to construct.
+   * @param bool $immutable
+   *   (optional) Create an immutable configuration object. Defaults to TRUE.
+   *
+   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
+   *   A configuration object.
+   */
+  protected function doGet($name, $immutable = TRUE) {
+    if ($config = $this->doLoadMultiple(array($name), $immutable)) {
       return $config[$name];
     }
     else {
       // If the configuration object does not exist in the configuration
       // storage, create a new object and add it to the static cache.
-      $cache_key = $this->getConfigCacheKey($name);
-      $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
+      $cache_key = $this->getConfigCacheKey($name, $immutable);
+      $this->cache[$cache_key] = $this->createConfigObject($name, $immutable);
 
       if ($this->useOverrides) {
         // Get and apply any overrides.
@@ -134,10 +160,25 @@ public function get($name) {
    * {@inheritdoc}
    */
   public function loadMultiple(array $names) {
+    return $this->doLoadMultiple($names);
+  }
+
+  /**
+   * Returns a list of configuration objects for the given names.
+   *
+   * @param array $names
+   *   List of names of configuration objects.
+   * @param bool $immutable
+   *   (optional) Create an immutable configuration objects. Defaults to TRUE.
+   *
+   * @return \Drupal\Core\Config\Config[]|\Drupal\Core\Config\ImmutableConfig[]
+   *   List of successfully loaded configuration objects, keyed by name.
+   */
+  protected function doLoadMultiple(array $names, $immutable = TRUE) {
     $list = array();
 
     foreach ($names as $key => $name) {
-      $cache_key = $this->getConfigCacheKey($name);
+      $cache_key = $this->getConfigCacheKey($name, $immutable);
       if (isset($this->cache[$cache_key])) {
         $list[$name] = $this->cache[$cache_key];
         unset($names[$key]);
@@ -156,9 +197,9 @@ public function loadMultiple(array $names) {
       }
 
       foreach ($storage_data as $name => $data) {
-        $cache_key = $this->getConfigCacheKey($name);
+        $cache_key = $this->getConfigCacheKey($name, $immutable);
 
-        $this->cache[$cache_key] = new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
+        $this->cache[$cache_key] = $this->createConfigObject($name, $immutable);
         $this->cache[$cache_key]->initWithData($data);
         if ($this->useOverrides) {
           if (isset($module_overrides[$name])) {
@@ -230,7 +271,7 @@ public function rename($old_name, $new_name) {
     // Prime the cache and load the configuration with the correct overrides.
     $config = $this->get($new_name);
     $this->eventDispatcher->dispatch(ConfigEvents::RENAME, new ConfigRenameEvent($config, $old_name));
-    return $config;
+    return $this;
   }
 
   /**
@@ -254,12 +295,14 @@ public function getCacheKeys() {
    *
    * @param string $name
    *   The name of the configuration object.
+   * @param bool $immutable
+   *   Whether or not the object is mutable.
    *
    * @return string
    *   The cache key.
    */
-  protected function getConfigCacheKey($name) {
-    return $name . ':' . implode(':', $this->getCacheKeys());
+  protected function getConfigCacheKey($name, $immutable) {
+    return $name . ':' . implode(':', $this->getCacheKeys()) . ':' . ($immutable ? static::IMMUTABLE: static::MUTABLE);
   }
 
   /**
@@ -294,7 +337,7 @@ public function listAll($prefix = '') {
   }
 
   /**
-   * Removes stale static cache entries when configuration is saved.
+   * Updates stale static cache entries when configuration is saved.
    *
    * @param ConfigCrudEvent $event
    *   The configuration event.
@@ -307,7 +350,9 @@ public function onConfigSave(ConfigCrudEvent $event) {
     foreach ($this->getConfigCacheKeys($saved_config->getName()) as $cache_key) {
       $cached_config = $this->cache[$cache_key];
       if ($cached_config !== $saved_config) {
-        $this->cache[$cache_key]->setData($saved_config->getRawData());
+        // We can not just update the data since other things about the object
+        // might have changed. For example, whether or not it is new.
+        $this->cache[$cache_key]->initWithData($saved_config->getRawData());
       }
     }
   }
@@ -341,4 +386,22 @@ public function addOverride(ConfigFactoryOverrideInterface $config_factory_overr
     $this->configFactoryOverrides[] = $config_factory_override;
   }
 
+  /**
+   * Creates a configuration object.
+   *
+   * @param string $name
+   *   Configuration object name.
+   * @param bool $immutable
+   *   Determines whether a mutable or immutable config object is returned.
+   *
+   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
+   *   The configuration object.
+   */
+  protected function createConfigObject($name, $immutable) {
+    if ($immutable) {
+      return new ImmutableConfig($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
+    }
+    return new Config($name, $this->storage, $this->eventDispatcher, $this->typedConfigManager);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php
index d51e02346864..f74be94117c0 100644
--- a/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php
+++ b/core/lib/Drupal/Core/Config/ConfigFactoryInterface.php
@@ -14,6 +14,16 @@
  */
 interface ConfigFactoryInterface {
 
+  /**
+   * Constant used in static cache keys for mutable config objects.
+   */
+  const MUTABLE = 'mutable';
+
+  /**
+   * Constant used in static cache keys for immutable config objects.
+   */
+  const IMMUTABLE = 'immutable';
+
   /**
    * Sets the override state.
    *
@@ -33,26 +43,42 @@ public function setOverrideState($state);
   public function getOverrideState();
 
   /**
-   * Returns a configuration object for a given name.
+   * Returns an immutable configuration object for a given name.
    *
    * @param string $name
    *   The name of the configuration object to construct.
    *
-   * @return \Drupal\Core\Config\Config
+   * @return \Drupal\Core\Config\ImmutableConfig
    *   A configuration object.
    */
   public function get($name);
 
+  /**
+   * Returns an mutable configuration object for a given name.
+   *
+   * Should not be used for config that will have runtime effects. Therefore it
+   * is always loaded override free.
+   *
+   * @param string $name
+   *   The name of the configuration object to construct.
+   *
+   * @return \Drupal\Core\Config\Config
+   *   A configuration object.
+   */
+  public function getEditable($name);
+
   /**
    * Returns a list of configuration objects for the given names.
    *
    * This will pre-load all requested configuration objects does not create
-   * new configuration objects.
+   * new configuration objects. This method always return immutable objects.
+   * ConfigFactoryInterface::getEditable() should be used to retrieve mutable
+   * configuration objects, one by one.
    *
    * @param array $names
    *   List of names of configuration objects.
    *
-   * @return \Drupal\Core\Config\Config[]
+   * @return \Drupal\Core\Config\ImmutableConfig[]
    *   List of successfully loaded configuration objects, keyed by name.
    */
   public function loadMultiple(array $names);
@@ -76,8 +102,7 @@ public function reset($name = NULL);
    * @param string $new_name
    *   The new name of the configuration object.
    *
-   * @return \Drupal\Core\Config\Config
-   *   The renamed config object.
+   * @return $this
    */
   public function rename($old_name, $new_name);
 
diff --git a/core/lib/Drupal/Core/Config/ConfigManager.php b/core/lib/Drupal/Core/Config/ConfigManager.php
index a97cf7288dd1..da0fa989289c 100644
--- a/core/lib/Drupal/Core/Config/ConfigManager.php
+++ b/core/lib/Drupal/Core/Config/ConfigManager.php
@@ -224,7 +224,7 @@ public function uninstall($type, $name) {
 
     $config_names = $this->configFactory->listAll($name . '.');
     foreach ($config_names as $config_name) {
-      $this->configFactory->get($config_name)->delete();
+      $this->configFactory->getEditable($config_name)->delete();
     }
 
     // Remove any matching configuration from collections.
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
index 7057491b7191..6626578a76a1 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityStorage.php
@@ -200,8 +200,7 @@ protected function doCreate(array $values) {
    */
   protected function doDelete($entities) {
     foreach ($entities as $entity) {
-      $config = $this->configFactory->get($this->getPrefix() . $entity->id());
-      $config->delete();
+      $this->configFactory->getEditable($this->getPrefix() . $entity->id())->delete();
     }
   }
 
@@ -238,16 +237,15 @@ public function save(EntityInterface $entity) {
   protected function doSave($id, EntityInterface $entity) {
     $is_new = $entity->isNew();
     $prefix = $this->getPrefix();
+    $config_name = $prefix . $entity->id();
     if ($id !== $entity->id()) {
       // Renaming a config object needs to cater for:
       // - Storage needs to access the original object.
       // - The object needs to be renamed/copied in ConfigFactory and reloaded.
       // - All instances of the object need to be renamed.
-      $config = $this->configFactory->rename($prefix . $id, $prefix . $entity->id());
-    }
-    else {
-      $config = $this->configFactory->get($prefix . $id);
+      $this->configFactory->rename($prefix . $id, $config_name);
     }
+    $config = $this->configFactory->getEditable($config_name);
 
     // Retrieve the desired properties and set them in config.
     $config->setData($this->mapToStorageRecord($entity));
diff --git a/core/lib/Drupal/Core/Config/ImmutableConfig.php b/core/lib/Drupal/Core/Config/ImmutableConfig.php
new file mode 100644
index 000000000000..61e7fdd099b9
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ImmutableConfig.php
@@ -0,0 +1,61 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ImmutableConfig.
+ */
+
+namespace Drupal\Core\Config;
+
+use Drupal\Component\Utility\String;
+
+/**
+ * Defines the immutable configuration object.
+ *
+ * Encapsulates all capabilities needed for runtime configuration handling
+ * except being able to change the configuration.
+ *
+ * If you need to be able to change configuration use
+ * \Drupal\Core\Form\ConfigFormBaseTrait or
+ * \Drupal\Core\Config\ConfigFactoryInterface::getEditable().
+ *
+ * @see \Drupal\Core\Form\ConfigFormBaseTrait
+ * @see \Drupal\Core\Config\ConfigFactoryInterface::getEditable()
+ * @see \Drupal\Core\Config\ConfigFactoryInterface::get()
+ *
+ * @ingroup config_api
+ */
+class ImmutableConfig extends Config {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function set($key, $value) {
+    throw new ImmutableConfigException(String::format('Can not set values on immutable configuration !name:!key. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName(), '!key' => $key]));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clear($key) {
+    throw new ImmutableConfigException(String::format('Can not clear !key key in immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName(), '!key' => $key]));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function save() {
+    throw new ImmutableConfigException(String::format('Can not save immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()]));
+  }
+
+  /**
+   * Deletes the configuration object.
+   *
+   * @return \Drupal\Core\Config\Config
+   *   The configuration object.
+   */
+  public function delete() {
+    throw new ImmutableConfigException(String::format('Can not delete immutable configuration !name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object', ['!name' => $this->getName()]));
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Config/ImmutableConfigException.php b/core/lib/Drupal/Core/Config/ImmutableConfigException.php
new file mode 100644
index 000000000000..4df074a55563
--- /dev/null
+++ b/core/lib/Drupal/Core/Config/ImmutableConfigException.php
@@ -0,0 +1,16 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Config\ImmutableConfigException.
+ */
+
+namespace Drupal\Core\Config;
+
+/**
+ * Exception throw when an immutable config object is altered.
+ *
+ * @see \Drupal\Core\Config\ImmutableConfig
+ */
+class ImmutableConfigException extends \LogicException {
+}
diff --git a/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
index 73278d32bf37..6cb8363e6d48 100644
--- a/core/lib/Drupal/Core/Extension/ModuleInstaller.php
+++ b/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -79,7 +79,7 @@ public function addUninstallValidator(ModuleUninstallValidatorInterface $uninsta
    * {@inheritdoc}
    */
   public function install(array $module_list, $enable_dependencies = TRUE) {
-    $extension_config = \Drupal::config('core.extension');
+    $extension_config = \Drupal::configFactory()->getEditable('core.extension');
     if ($enable_dependencies) {
       // Get all module data so we can find dependencies and sort.
       $module_data = system_rebuild_module_data();
@@ -300,8 +300,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       return FALSE;
     }
 
-    // Only process currently installed modules.
-    $extension_config = \Drupal::config('core.extension');
+    $extension_config = \Drupal::configFactory()->getEditable('core.extension');
     $installed_modules = $extension_config->get('module') ?: array();
     if (!$module_list = array_intersect_key($module_list, $installed_modules)) {
       // Nothing to do. All modules already uninstalled.
@@ -387,8 +386,7 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       drupal_uninstall_schema($module);
 
       // Remove the module's entry from the config.
-      $extension_config = \Drupal::config('core.extension');
-      $extension_config->clear("module.$module")->save();
+      \Drupal::configFactory()->getEditable('core.extension')->clear("module.$module")->save();
 
       // Update the module handler to remove the module.
       // The current ModuleHandler instance is obsolete with the kernel rebuild
diff --git a/core/lib/Drupal/Core/Extension/ThemeHandler.php b/core/lib/Drupal/Core/Extension/ThemeHandler.php
index 89ad50319ebd..2f0fd9498ab6 100644
--- a/core/lib/Drupal/Core/Extension/ThemeHandler.php
+++ b/core/lib/Drupal/Core/Extension/ThemeHandler.php
@@ -179,7 +179,7 @@ public function setDefault($name) {
     if (!isset($list[$name])) {
       throw new \InvalidArgumentException("$name theme is not installed.");
     }
-    $this->configFactory->get('system.theme')
+    $this->configFactory->getEditable('system.theme')
       ->set('default', $name)
       ->save();
     return $this;
@@ -189,7 +189,7 @@ public function setDefault($name) {
    * {@inheritdoc}
    */
   public function install(array $theme_list, $install_dependencies = TRUE) {
-    $extension_config = $this->configFactory->get('core.extension');
+    $extension_config = $this->configFactory->getEditable('core.extension');
 
     $theme_data = $this->rebuildThemeData();
 
@@ -313,8 +313,8 @@ public function install(array $theme_list, $install_dependencies = TRUE) {
    * {@inheritdoc}
    */
   public function uninstall(array $theme_list) {
-    $extension_config = $this->configFactory->get('core.extension');
-    $theme_config = $this->configFactory->get('system.theme');
+    $extension_config = $this->configFactory->getEditable('core.extension');
+    $theme_config = $this->configFactory->getEditable('system.theme');
     $list = $this->listInfo();
     foreach ($theme_list as $key) {
       if (!isset($list[$key])) {
diff --git a/core/lib/Drupal/Core/Form/ConfigFormBase.php b/core/lib/Drupal/Core/Form/ConfigFormBase.php
index f58bc11b6e44..5ed650a613ca 100644
--- a/core/lib/Drupal/Core/Form/ConfigFormBase.php
+++ b/core/lib/Drupal/Core/Form/ConfigFormBase.php
@@ -15,6 +15,7 @@
  * Base class for implementing system configuration forms.
  */
 abstract class ConfigFormBase extends FormBase {
+  use ConfigFormBaseTrait;
 
   /**
    * Constructs a \Drupal\system\ConfigFormBase object.
@@ -59,20 +60,4 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The configuration options have been saved.'));
   }
 
-  /**
-   * {@inheritdoc}
-   *
-   * Overrides \Drupal\Core\Form\FormBase::config() so that configuration is
-   * returned override free. This ensures that overrides do not pollute saved
-   * configuration.
-   */
-  protected function config($name) {
-    $config_factory = $this->configFactory();
-    $old_state = $config_factory->getOverrideState();
-    $config_factory->setOverrideState(FALSE);
-    $config = $config_factory->get($name);
-    $config_factory->setOverrideState($old_state);
-    return $config;
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php b/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php
new file mode 100644
index 000000000000..1cbac3c27c05
--- /dev/null
+++ b/core/lib/Drupal/Core/Form/ConfigFormBaseTrait.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Form\ConfigFormBaseTrait.
+ */
+
+namespace Drupal\Core\Form;
+
+use Drupal\Core\Config\ConfigFactoryInterface;
+
+/**
+ * Provides access to configuration for forms.
+ *
+ * This trait provides a config() method that returns override free and mutable
+ * config objects if the configuration name is in the array returned by the
+ * getEditableConfigNames() implementation.
+ *
+ * Forms that present configuration to the user have to take care not to save
+ * configuration overrides to the stored configuration since overrides are often
+ * environment specific. Default values of form elements should be obtained from
+ * override free configuration objects. However, if a form reacts to
+ * configuration in any way, for example sends an email to the system.site:mail
+ * address, then it is important that the value comes from a configuration
+ * object with overrides. Therefore, override free and editable configuration
+ * objects are limited to those listed by the getEditableConfigNames() method.
+ */
+trait ConfigFormBaseTrait {
+
+  /**
+   * Retrieves a configuration object.
+   *
+   * Objects that use the trait need to implement the
+   * \Drupal\Core\Form\ConfigFormBaseTrait::getEditableConfigNames() to declare
+   * which configuration objects this method returns override free and mutable.
+   * This ensures that overrides do not pollute saved configuration.
+   *
+   * @param string $name
+   *   The name of the configuration object to retrieve. The name corresponds to
+   *   a configuration file. For @code \Drupal::config('book.admin') @endcode,
+   *   the config object returned will contain the contents of book.admin
+   *   configuration file.
+   *
+   * @return \Drupal\Core\Config\Config|\Drupal\Core\Config\ImmutableConfig
+   *   A configuration object.
+   */
+  protected function config($name) {
+    /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
+    if (method_exists($this, 'configFactory')) {
+      $config_factory = $this->configFactory();
+    }
+    elseif (property_exists($this, 'configFactory')) {
+      $config_factory = $this->configFactory;
+    }
+    if (!isset($config_factory) || !($config_factory instanceof ConfigFactoryInterface)) {
+      throw new \LogicException('No config factory available for ConfigFormBaseTrait');
+    }
+    if (in_array($name, $this->getEditableConfigNames())) {
+      // Get a mutable object from the factory.
+      $config = $config_factory->getEditable($name);
+    }
+    else {
+      $config = $config_factory->get($name);
+    }
+    return $config;
+  }
+
+  /**
+   * Gets the configuration names that will be editable.
+   *
+   * @return array
+   *   An array of configuration object names that are editable if called in
+   *   conjunction with the trait's config() method.
+   */
+  abstract protected function getEditableConfigNames();
+
+}
diff --git a/core/lib/Drupal/Core/Form/FormBase.php b/core/lib/Drupal/Core/Form/FormBase.php
index b60e9ed32cc6..d7c2bfde84ae 100644
--- a/core/lib/Drupal/Core/Form/FormBase.php
+++ b/core/lib/Drupal/Core/Form/FormBase.php
@@ -87,7 +87,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
    *   the config object returned will contain the contents of book.admin
    *   configuration file.
    *
-   * @return \Drupal\Core\Config\Config
+   * @return \Drupal\Core\Config\ImmutableConfig
    *   A configuration object.
    */
   protected function config($name) {
diff --git a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
index ba55764d4cfa..0354e25491fc 100644
--- a/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
+++ b/core/lib/Drupal/Core/Installer/Form/SiteConfigureForm.php
@@ -97,6 +97,17 @@ public function getFormId() {
     return 'install_configure_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return [
+      'system.date',
+      'system.site',
+      'update.settings',
+    ];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php
index 789e25845deb..a52601cdd79d 100644
--- a/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php
+++ b/core/lib/Drupal/Core/Menu/StaticMenuLinkOverrides.php
@@ -17,6 +17,10 @@ class StaticMenuLinkOverrides implements StaticMenuLinkOverridesInterface {
   /**
    * The config name used to store the overrides.
    *
+   * This configuration can not be overridden by configuration overrides because
+   * menu links and these overrides are cached in a way that is not override
+   * aware.
+   *
    * @var string
    */
   protected $configName = 'core.menu.static_menu_link_overrides';
@@ -54,7 +58,8 @@ public function __construct(ConfigFactoryInterface $config_factory) {
    */
   protected function getConfig() {
     if (empty($this->config)) {
-      $this->config = $this->configFactory->get($this->configName);
+      // Get an override free and editable configuration object.
+      $this->config = $this->configFactory->getEditable($this->configName);
     }
     return $this->config;
   }
diff --git a/core/modules/aggregator/src/Form/SettingsForm.php b/core/modules/aggregator/src/Form/SettingsForm.php
index ff6fd624f2dc..69c5ed67ad60 100644
--- a/core/modules/aggregator/src/Form/SettingsForm.php
+++ b/core/modules/aggregator/src/Form/SettingsForm.php
@@ -96,6 +96,13 @@ public function getFormId() {
     return 'aggregator_admin_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['aggregator.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php b/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
index c31b4ff46eba..cadd84b721d6 100644
--- a/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
+++ b/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
@@ -16,6 +16,7 @@
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Datetime\DateFormatter;
 use Drupal\Core\Entity\Query\QueryInterface;
+use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\UrlGeneratorTrait;
@@ -33,7 +34,7 @@
  * )
  */
 class DefaultProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface {
-
+  use ConfigFormBaseTrait;
   use UrlGeneratorTrait;
 
   /**
@@ -107,11 +108,19 @@ public static function create(ContainerInterface $container, array $configuratio
     );
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['aggregator.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
-    $processors = $this->configuration['processors'];
+    $config = $this->config('aggregator.settings');
+    $processors = $config->get('processors');
     $info = $this->getPluginDefinition();
     $counts = array(3, 5, 10, 15, 20, 25);
     $items = array_map(function ($count) {
@@ -135,7 +144,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $form['processors'][$info['id']]['aggregator_summary_items'] = array(
       '#type' => 'select',
       '#title' => t('Number of items shown in listing pages'),
-      '#default_value' => $this->configuration['source']['list_max'],
+      '#default_value' => $config->get('source.list_max'),
       '#empty_value' => 0,
       '#options' => $items,
     );
@@ -143,7 +152,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $form['processors'][$info['id']]['aggregator_clear'] = array(
       '#type' => 'select',
       '#title' => t('Discard items older than'),
-      '#default_value' => $this->configuration['items']['expire'],
+      '#default_value' => $config->get('items.expire'),
       '#options' => $period,
       '#description' => t('Requires a correctly configured <a href="@cron">cron maintenance task</a>.', array('@cron' => $this->url('system.status'))),
     );
@@ -156,7 +165,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $form['processors'][$info['id']]['aggregator_teaser_length'] = array(
       '#type' => 'select',
       '#title' => t('Length of trimmed description'),
-      '#default_value' => $this->configuration['items']['teaser_length'],
+      '#default_value' => $config->get('items.teaser_length'),
       '#options' => $options,
       '#description' => t('The maximum number of characters used in the trimmed version of content.'),
     );
@@ -275,7 +284,7 @@ public function getConfiguration() {
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $config = $this->configFactory->get('aggregator.settings');
+    $config = $this->config('aggregator.settings');
     foreach ($configuration as $key => $value) {
       $config->set($key, $value);
     }
diff --git a/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php b/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php
index c9307015f3b4..1a6ee19b4f32 100644
--- a/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php
+++ b/core/modules/aggregator/tests/modules/aggregator_test/src/Plugin/aggregator/processor/TestProcessor.php
@@ -11,6 +11,7 @@
 use Drupal\aggregator\Plugin\ProcessorInterface;
 use Drupal\aggregator\FeedInterface;
 use Drupal\Core\Config\ConfigFactoryInterface;
+use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -27,6 +28,7 @@
  * )
  */
 class TestProcessor extends AggregatorPluginSettingsBase implements ProcessorInterface, ContainerFactoryPluginInterface {
+  use ConfigFormBaseTrait;
 
   /**
    * Contains the configuration object factory.
@@ -64,11 +66,18 @@ public function __construct(array $configuration, $plugin_id, $plugin_definition
     parent::__construct($configuration + $this->getConfiguration(), $plugin_id, $plugin_definition);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['aggregator_test.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
   public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
-    $processors = $this->configFactory->get('aggregator.settings')->get('processors');
+    $processors = $this->config('aggregator.settings')->get('processors');
     $info = $this->getPluginDefinition();
 
     $form['processors'][$info['id']] = array(
@@ -134,7 +143,7 @@ public function getConfiguration() {
    * {@inheritdoc}
    */
   public function setConfiguration(array $configuration) {
-    $config = $this->configFactory->get('aggregator_test.settings');
+    $config = $this->config('aggregator_test.settings');
     foreach ($configuration as $key => $value) {
       $config->set($key, $value);
     }
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 9c7ab5503f49..a11f74d4928d 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -559,7 +559,7 @@ function book_type_is_allowed($type) {
  */
 function book_node_type_update(NodeTypeInterface $type) {
   if ($type->getOriginalId() != $type->id()) {
-    $config = \Drupal::config('book.settings');
+    $config = \Drupal::configFactory()->getEditable('book.settings');
     // Update the list of node types that are allowed to be added to books.
     $allowed_types = $config->get('allowed_types');
     $old_key = array_search($type->getOriginalId(), $allowed_types);
diff --git a/core/modules/book/src/Form/BookSettingsForm.php b/core/modules/book/src/Form/BookSettingsForm.php
index fe1db372b7d4..0db0dc5ca950 100644
--- a/core/modules/book/src/Form/BookSettingsForm.php
+++ b/core/modules/book/src/Form/BookSettingsForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'book_admin_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['book.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/ckeditor/src/Tests/CKEditorTest.php b/core/modules/ckeditor/src/Tests/CKEditorTest.php
index dc5f2350edfc..572e8abf242f 100644
--- a/core/modules/ckeditor/src/Tests/CKEditorTest.php
+++ b/core/modules/ckeditor/src/Tests/CKEditorTest.php
@@ -402,7 +402,7 @@ function testJSTranslation() {
   protected function assertCKEditorLanguage($langcode = 'fr') {
     // Set French as the site default language.
     ConfigurableLanguage::createFromLangcode('fr')->save();
-    \Drupal::config('system.site')->set('langcode', 'fr')->save();
+    $this->config('system.site')->set('langcode', 'fr')->save();
 
     // Reset the language manager so new negotiations attempts will fall back on
     // French. Reinject the language manager CKEditor to use the current one.
diff --git a/core/modules/color/color.module b/core/modules/color/color.module
index 5ad67f2084f1..8bbb03551a2b 100644
--- a/core/modules/color/color.module
+++ b/core/modules/color/color.module
@@ -169,7 +169,10 @@ function color_get_palette($theme, $default = FALSE) {
 
   // Load variable.
   // @todo Default color config should be moved to yaml in the theme.
-  return \Drupal::config('color.theme.' . $theme)->get('palette') ?: $palette;
+  // Getting a mutable override-free object because this function is only used
+  // in forms. Color configuration is used to write CSS to the file system
+  // making configuration overrides pointless.
+  return \Drupal::configFactory()->getEditable('color.theme.' . $theme)->get('palette') ?: $palette;
 }
 
 /**
@@ -196,7 +199,11 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them
 
   // See if we're using a predefined scheme.
   // Note: we use the original theme when the default scheme is chosen.
-  $current_scheme = \Drupal::config('color.theme.' . $theme)->get('palette');
+  // Note: we use configuration without overrides since this information is used
+  // in a form and therefore without doing this would bleed overrides into
+  // active configuration. Furthermore, color configuration is used to write
+  // CSS to the file system making configuration overrides pointless.
+  $current_scheme = \Drupal::configFactory()->getEditable('color.theme.' . $theme)->get('palette');
   foreach ($schemes as $key => $scheme) {
     if ($current_scheme == $scheme) {
       $scheme_name = $key;
@@ -213,6 +220,7 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them
   }
 
   // Add scheme selector.
+  $default_palette = color_get_palette($theme, TRUE);
   $form['scheme'] = array(
     '#type' => 'select',
     '#title' => t('Color set'),
@@ -226,7 +234,7 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them
       // Add custom JavaScript.
       'drupalSettings' => [
         'color' => [
-          'reference' => color_get_palette($theme, TRUE),
+          'reference' => $default_palette,
           'schemes' => $schemes,
         ],
         'gradients' => $info['gradients'],
@@ -234,8 +242,8 @@ function color_scheme_form($complete_form, FormStateInterface $form_state, $them
     ),
   );
 
-  // Add palette fields.
-  $palette = color_get_palette($theme);
+  // Add palette fields. Use the configuration if available.
+  $palette = $current_scheme ?: $default_palette;
   $names = $info['fields'];
   $form['palette']['#tree'] = TRUE;
   foreach ($palette as $name => $value) {
@@ -361,7 +369,7 @@ function color_scheme_form_submit($form, FormStateInterface $form_state) {
     return;
   }
 
-  $config = \Drupal::config('color.theme.' . $theme);
+  $config = \Drupal::configFactory()->getEditable('color.theme.' . $theme);
 
   // Resolve palette.
   if ($scheme != '') {
@@ -620,7 +628,7 @@ function _color_render_images($theme, &$info, &$paths, $palette) {
     if ($file == 'screenshot.png') {
       $slice = imagecreatetruecolor(150, 90);
       imagecopyresampled($slice, $target, 0, 0, $x, $y, 150, 90, $width, $height);
-      \Drupal::config('color.theme.' . $theme)
+      \Drupal::configFactory()->getEditable('color.theme.' . $theme)
         ->set('screenshot', $image)
         ->save();
     }
diff --git a/core/modules/config/src/Form/ConfigSingleImportForm.php b/core/modules/config/src/Form/ConfigSingleImportForm.php
index 58156b094bce..ee1dfde1603f 100644
--- a/core/modules/config/src/Form/ConfigSingleImportForm.php
+++ b/core/modules/config/src/Form/ConfigSingleImportForm.php
@@ -243,7 +243,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
 
     // If a simple configuration file was added, set the data and save.
     if ($this->data['config_type'] === 'system.simple') {
-      $this->config($this->data['config_name'])->setData($this->data['import'])->save();
+      $this->configFactory()->getEditable($this->data['config_name'])->setData($this->data['import'])->save();
       drupal_set_message($this->t('The %name configuration was imported.', array('%name' => $this->data['config_name'])));
     }
     // For a config entity, create an entity and save it.
diff --git a/core/modules/config/src/Tests/ConfigCRUDTest.php b/core/modules/config/src/Tests/ConfigCRUDTest.php
index 25391fef7cf3..f54caed17183 100644
--- a/core/modules/config/src/Tests/ConfigCRUDTest.php
+++ b/core/modules/config/src/Tests/ConfigCRUDTest.php
@@ -249,7 +249,7 @@ public function testDataTypes() {
     \Drupal::service('module_installer')->install(array('config_test'));
     $storage = new DatabaseStorage($this->container->get('database'), 'config');
     $name = 'config_test.types';
-    $config = $this->container->get('config.factory')->get($name);
+    $config = $this->config($name);
     $original_content = file_get_contents(drupal_get_path('module', 'config_test') . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY . "/$name.yml");
     $this->verbose('<pre>' . $original_content . "\n" . var_export($storage->read($name), TRUE));
 
@@ -299,7 +299,7 @@ public function testDataTypes() {
     // also fails.
     $typed_config_manager = $this->container->get('config.typed');
     $config_name = 'config_test.no_schema';
-    $config = $this->container->get('config.factory')->get($config_name);
+    $config = $this->config($config_name);
     $this->assertFalse($typed_config_manager->hasConfigSchema($config_name));
 
     try {
diff --git a/core/modules/config/src/Tests/ConfigEventsTest.php b/core/modules/config/src/Tests/ConfigEventsTest.php
index b4f72794ad1a..fb6eca61eaf7 100644
--- a/core/modules/config/src/Tests/ConfigEventsTest.php
+++ b/core/modules/config/src/Tests/ConfigEventsTest.php
@@ -67,11 +67,14 @@ function testConfigRenameEvent() {
     $GLOBALS['config'][$name] = array('key' => 'overridden');
     $GLOBALS['config'][$new_name] = array('key' => 'new overridden');
 
-    $config = \Drupal::config($name);
+    $config = $this->config($name);
     $config->set('key', 'initial')->save();
     $event = \Drupal::state()->get('config_events_test.event', array());
     $this->assertIdentical($event['event_name'], ConfigEvents::SAVE);
-    $this->assertIdentical($event['current_config_data'], array('key' => 'overridden'));
+    $this->assertIdentical($event['current_config_data'], array('key' => 'initial'));
+
+    // Override applies when getting runtime config.
+    $this->assertEqual($GLOBALS['config'][$name], \Drupal::config($name)->get());
 
     \Drupal::configFactory()->rename($name, $new_name);
     $event = \Drupal::state()->get('config_events_test.event', array());
diff --git a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
index 9de963cc77f6..cc754d4b3c9d 100644
--- a/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
+++ b/core/modules/config/src/Tests/ConfigLanguageOverrideTest.php
@@ -76,7 +76,7 @@ function testConfigLanguageOverride() {
 
     // Test how overrides react to base configuration changes. Set up some base
     // values.
-    \Drupal::config('config_test.foo')
+    \Drupal::configFactory()->getEditable('config_test.foo')
       ->set('value', array('key' => 'original'))
       ->set('label', 'Original')
       ->save();
@@ -94,6 +94,7 @@ function testConfigLanguageOverride() {
     $this->assertIdentical($config->get('value'), array('key' => 'override'));
 
     // Ensure renaming the config will rename the override.
+    \Drupal::languageManager()->setConfigOverrideLanguage(language_load('en'));
     \Drupal::configFactory()->rename('config_test.foo', 'config_test.bar');
     $config = \Drupal::config('config_test.bar');
     $this->assertEqual($config->get('value'), array('key' => 'original'));
@@ -108,7 +109,7 @@ function testConfigLanguageOverride() {
     $this->assertEqual($override->get('value'), array('key' => 'override'));
 
     // Ensure changing data in the config will update the overrides.
-    $config = \Drupal::config('config_test.bar')->clear('value.key')->save();
+    $config = \Drupal::configFactory()->getEditable('config_test.bar')->clear('value.key')->save();
     $this->assertEqual($config->get('value'), array());
     $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
     $this->assertFalse($override->isNew());
@@ -119,7 +120,7 @@ function testConfigLanguageOverride() {
     $this->assertEqual($override->get('value'), NULL);
 
     // Ensure deleting the config will delete the override.
-    \Drupal::configFactory()->get('config_test.bar')->delete();
+    \Drupal::configFactory()->getEditable('config_test.bar')->delete();
     $override = \Drupal::languageManager()->getLanguageConfigOverride('de', 'config_test.bar');
     $this->assertTrue($override->isNew());
     $this->assertEqual($override->get('value'), NULL);
diff --git a/core/modules/config/src/Tests/ConfigModuleOverridesTest.php b/core/modules/config/src/Tests/ConfigModuleOverridesTest.php
index 41f144c32b03..923b2f0deeee 100644
--- a/core/modules/config/src/Tests/ConfigModuleOverridesTest.php
+++ b/core/modules/config/src/Tests/ConfigModuleOverridesTest.php
@@ -32,7 +32,7 @@ public function testSimpleModuleOverrides() {
     $non_overridden_slogan = 'Yay for defaults!';
     $config_factory = $this->container->get('config.factory');
     $config_factory
-      ->get($name)
+      ->getEditable($name)
       ->set('name', $non_overridden_name)
       ->set('slogan', $non_overridden_slogan)
       ->save();
diff --git a/core/modules/config/src/Tests/ConfigOverrideTest.php b/core/modules/config/src/Tests/ConfigOverrideTest.php
index 38ba0a1e581f..75088962ddca 100644
--- a/core/modules/config/src/Tests/ConfigOverrideTest.php
+++ b/core/modules/config/src/Tests/ConfigOverrideTest.php
@@ -55,14 +55,22 @@ function testConfOverride() {
     $this->assertFalse(isset($data['baz']));
     $this->assertIdentical($data['404'], $expected_original_data['404']);
 
-    // Get the configuration object in with overrides.
-    $config = \Drupal::config('config_test.system');
+    // Get the configuration object with overrides.
+    $config = \Drupal::configFactory()->get('config_test.system');
 
     // Verify that it contains the overridden data from $config.
     $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
     $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
     $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
 
+    // Get the configuration object which does not have overrides.
+    $config = \Drupal::configFactory()->getEditable('config_test.system');
+
+    // Verify that it does not contains the overridden data from $config.
+    $this->assertIdentical($config->get('foo'), $expected_original_data['foo']);
+    $this->assertIdentical($config->get('baz'), NULL);
+    $this->assertIdentical($config->get('404'), $expected_original_data['404']);
+
     // Set the value for 'baz' (on the original data).
     $expected_original_data['baz'] = 'original baz';
     $config->set('baz', $expected_original_data['baz']);
@@ -71,11 +79,6 @@ function testConfOverride() {
     $expected_original_data['404'] = 'original 404';
     $config->set('404', $expected_original_data['404']);
 
-    // Verify that it still contains the overridden data from $config.
-    $this->assertIdentical($config->get('foo'), $overrides['config_test.system']['foo']);
-    $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
-    $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
-
     // Save the configuration object (having overrides applied).
     $config->save();
 
@@ -85,6 +88,11 @@ function testConfOverride() {
     $this->assertIdentical($config->get('baz'), $overrides['config_test.system']['baz']);
     $this->assertIdentical($config->get('404'), $overrides['config_test.system']['404']);
 
+    // Verify that raw config data has changed.
+    $this->assertIdentical($config->getOriginal('foo', FALSE), $expected_original_data['foo']);
+    $this->assertIdentical($config->getOriginal('baz', FALSE), $expected_original_data['baz']);
+    $this->assertIdentical($config->getOriginal('404', FALSE), $expected_original_data['404']);
+
     // Write file to staging.
     $staging = $this->container->get('config.storage.staging');
     $expected_new_data = array(
@@ -118,7 +126,7 @@ function testConfOverride() {
     $this->assertIdentical($config->get('key'), 'override');
     $old_state = \Drupal::configFactory()->getOverrideState();
     \Drupal::configFactory()->setOverrideState(FALSE);
-    $config_raw = \Drupal::config('config_test.new');
+    $config_raw = \Drupal::configFactory()->getEditable('config_test.new');
     $this->assertIdentical($config_raw->get('key'), NULL);
     $config_raw
       ->set('key', 'raw')
diff --git a/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php b/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php
index 1fd05fa4dc2c..0cf8f0bcb487 100644
--- a/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php
+++ b/core/modules/config/src/Tests/ConfigOverridesPriorityTest.php
@@ -41,7 +41,7 @@ public function testOverridePriorities() {
     /** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
     $config_factory = $this->container->get('config.factory');
     $config_factory
-      ->get('system.site')
+      ->getEditable('system.site')
       ->set('name', $non_overridden_name)
       ->set('slogan', $non_overridden_slogan)
       ->set('mail', $non_overridden_mail)
diff --git a/core/modules/config/tests/config_test/src/SchemaListenerController.php b/core/modules/config/tests/config_test/src/SchemaListenerController.php
index baf297039777..1a6b28c3f827 100644
--- a/core/modules/config/tests/config_test/src/SchemaListenerController.php
+++ b/core/modules/config/tests/config_test/src/SchemaListenerController.php
@@ -7,20 +7,41 @@
 
 namespace Drupal\config_test;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Config\Schema\SchemaIncompleteException;
 use Drupal\Core\Controller\ControllerBase;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Controller for testing \Drupal\Core\Config\Testing\ConfigSchemaChecker.
  */
 class SchemaListenerController extends ControllerBase {
 
+  /**
+   * Constructs the SchemaListenerController object.
+   *
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
+   */
+  public function __construct(ConfigFactoryInterface $config_factory) {
+    $this->configFactory = $config_factory;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('config.factory')
+    );
+  }
+
   /**
    * Tests the WebTestBase tests can use strict schema checking.
    */
   public function test() {
     try {
-      $this->config('config_schema_test.schemaless')->set('foo', 'bar')->save();
+      $this->configFactory->getEditable('config_schema_test.schemaless')->set('foo', 'bar')->save();
     }
     catch (SchemaIncompleteException $e) {
       return [
diff --git a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
index 5a5f896eb676..e1ce0f632e92 100644
--- a/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
+++ b/core/modules/config_translation/src/Tests/ConfigTranslationUiTest.php
@@ -759,7 +759,7 @@ public function testTextFormatTranslation() {
     // security vulnerabilities.
     $config_factory
       ->setOverrideState(FALSE)
-      ->get('config_translation_test.content')
+      ->getEditable('config_translation_test.content')
       ->set('content.format', 'full_html')
       ->save();
 
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index c56633f860da..7444b6ef0e53 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -181,7 +181,7 @@ function contact_user_profile_form_submit($form, FormStateInterface $form_state)
  *
  * Add the default personal contact setting on the user settings page.
  *
- * @see user_admin_settings()
+ * @see \Drupal\user\AccountSettingsForm
  */
 function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form_state) {
   $form['contact'] = array(
@@ -194,7 +194,7 @@ function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form
     '#type' => 'checkbox',
     '#title' => t('Enable the personal contact form by default for new users'),
     '#description' => t('Changing this setting will not affect existing users.'),
-    '#default_value' => \Drupal::config('contact.settings')->get('user_default_enabled'),
+    '#default_value' => \Drupal::configFactory()->getEditable('contact.settings')->get('user_default_enabled'),
   );
   // Add submit handler to save contact configuration.
   $form['#submit'][] = 'contact_form_user_admin_settings_submit';
@@ -206,7 +206,7 @@ function contact_form_user_admin_settings_alter(&$form, FormStateInterface $form
  * @see contact_form_user_admin_settings_alter()
  */
 function contact_form_user_admin_settings_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('contact.settings')
+  \Drupal::configFactory()->getEditable('contact.settings')
     ->set('user_default_enabled', $form_state->getValue('contact_default_status'))
     ->save();
 }
diff --git a/core/modules/contact/src/ContactFormEditForm.php b/core/modules/contact/src/ContactFormEditForm.php
index 123ba38cc314..420be7da1f8f 100644
--- a/core/modules/contact/src/ContactFormEditForm.php
+++ b/core/modules/contact/src/ContactFormEditForm.php
@@ -7,14 +7,25 @@
 
 namespace Drupal\contact;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Entity\EntityForm;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\FormStateInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Base form for contact form edit forms.
  */
 class ContactFormEditForm extends EntityForm {
+  use ConfigFormBaseTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['contact.settings'];
+  }
 
   /**
    * {@inheritdoc}
diff --git a/core/modules/dblog/dblog.module b/core/modules/dblog/dblog.module
index e8568d4c5d43..570aaa401671 100644
--- a/core/modules/dblog/dblog.module
+++ b/core/modules/dblog/dblog.module
@@ -98,7 +98,7 @@ function dblog_form_system_logging_settings_alter(&$form, FormStateInterface $fo
   $form['dblog_row_limit'] = array(
     '#type' => 'select',
     '#title' => t('Database log messages to keep'),
-    '#default_value' => \Drupal::config('dblog.settings')->get('row_limit'),
+    '#default_value' => \Drupal::configFactory()->getEditable('dblog.settings')->get('row_limit'),
     '#options' => array(0 => t('All')) + array_combine($row_limits, $row_limits),
     '#description' => t('The maximum number of messages to keep in the database log. Requires a <a href="@cron">cron maintenance task</a>.', array('@cron' => \Drupal::url('system.status')))
   );
@@ -112,5 +112,5 @@ function dblog_form_system_logging_settings_alter(&$form, FormStateInterface $fo
  * @see dblog_form_system_logging_settings_alter()
  */
 function dblog_logging_settings_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('dblog.settings')->set('row_limit', $form_state->getValue('dblog_row_limit'))->save();
+  \Drupal::configFactory()->getEditable('dblog.settings')->set('row_limit', $form_state->getValue('dblog_row_limit'))->save();
 }
diff --git a/core/modules/forum/src/ForumSettingsForm.php b/core/modules/forum/src/ForumSettingsForm.php
index 77f176ddd3e6..f2b43c4a9334 100644
--- a/core/modules/forum/src/ForumSettingsForm.php
+++ b/core/modules/forum/src/ForumSettingsForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'forum_admin_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['forum.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index ddf580403110..d0b9aabc4b1c 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -339,7 +339,9 @@ function language_negotiation_url_prefixes_update() {
  * Saves language prefix settings.
  */
 function language_negotiation_url_prefixes_save(array $prefixes) {
-  \Drupal::config('language.negotiation')
+  // @todo https://www.drupal.org/node/2403229 $prefixes can contain
+  //   configuration overrides.
+  \Drupal::configFactory()->getEditable('language.negotiation')
   ->set('url.prefixes', $prefixes)
   ->save();
 }
@@ -355,7 +357,9 @@ function language_negotiation_url_domains() {
  * Saves the language domain settings.
  */
 function language_negotiation_url_domains_save(array $domains) {
-  \Drupal::config('language.negotiation')
+  // @todo https://www.drupal.org/node/2403229 $domains can contain
+  //   configuration overrides.
+  \Drupal::configFactory()->getEditable('language.negotiation')
   ->set('url.domains', $domains)
   ->save();
 }
@@ -492,7 +496,7 @@ function language_form_alter(&$form, FormStateInterface $form_state) {
  * @see language_form_system_regional_settings_alter()
  */
 function language_system_regional_settings_form_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('system.site')->set('langcode', $form_state->getValue('site_default_language'))->save();
+  \Drupal::configFactory()->getEditable('system.site')->set('langcode', $form_state->getValue('site_default_language'))->save();
 }
 
 /**
diff --git a/core/modules/language/src/ConfigurableLanguageInterface.php b/core/modules/language/src/ConfigurableLanguageInterface.php
index a4b794e1aa0a..994f6c1fa651 100644
--- a/core/modules/language/src/ConfigurableLanguageInterface.php
+++ b/core/modules/language/src/ConfigurableLanguageInterface.php
@@ -16,4 +16,15 @@
  */
 interface ConfigurableLanguageInterface extends ConfigEntityInterface, LanguageInterface {
 
+  /**
+   * Sets the weight of the language.
+   *
+   * @param int $weight
+   *   The weight, used to order languages with larger positive weights sinking
+   *   items toward the bottom of lists.
+   *
+   * @return $this
+   */
+  public function setWeight($weight);
+
 }
diff --git a/core/modules/language/src/ConfigurableLanguageManager.php b/core/modules/language/src/ConfigurableLanguageManager.php
index e17b3d2eda9b..a4ca11b6a761 100644
--- a/core/modules/language/src/ConfigurableLanguageManager.php
+++ b/core/modules/language/src/ConfigurableLanguageManager.php
@@ -195,7 +195,7 @@ public function getDefinedLanguageTypesInfo() {
    * {@inheritdoc}
    */
   public function saveLanguageTypesConfiguration(array $values) {
-    $config = $this->configFactory->get('language.types');
+    $config = $this->configFactory->getEditable('language.types');
     if (isset($values['configurable'])) {
       $config->set('configurable', $values['configurable']);
     }
@@ -343,23 +343,21 @@ public function getNativeLanguages() {
    * {@inheritdoc}
    */
   public function updateLockedLanguageWeights() {
-    $max_weight = 0;
+    // Get the weight of the last configurable language.
+    $configurable_languages = $this->getLanguages(LanguageInterface::STATE_CONFIGURABLE);
+    $max_weight = end($configurable_languages)->getWeight();
 
-    // Get maximum weight to update the system languages to keep them on bottom.
-    foreach ($this->getLanguages(LanguageInterface::STATE_CONFIGURABLE) as $language) {
-      if (!$language->isLocked()) {
-        $max_weight = max($max_weight, $language->getWeight());
-      }
-    }
-
-    // Loop locked languages to maintain the existing order.
     $locked_languages = $this->getLanguages(LanguageInterface::STATE_LOCKED);
-    $config_ids = array_map(function($language) { return 'language.entity.' . $language->getId(); }, $locked_languages);
-    foreach ($this->configFactory->loadMultiple($config_ids) as $config) {
-      // Update system languages weight.
-      $max_weight++;
-      $config->set('weight', $max_weight);
-      $config->save();
+    // Update locked language weights to maintain the existing order, if
+    // necessary.
+    if (reset($locked_languages)->getWeight() <= $max_weight) {
+      foreach ($locked_languages as $language) {
+        // Update system languages weight.
+        $max_weight++;
+        ConfigurableLanguage::load($language->getId())
+          ->setWeight($max_weight)
+          ->save();
+      }
     }
   }
 
diff --git a/core/modules/language/src/Entity/ConfigurableLanguage.php b/core/modules/language/src/Entity/ConfigurableLanguage.php
index f2e128ba3455..e52f763946c4 100644
--- a/core/modules/language/src/Entity/ConfigurableLanguage.php
+++ b/core/modules/language/src/Entity/ConfigurableLanguage.php
@@ -130,7 +130,7 @@ public function postSave(EntityStorageInterface $storage, $update = TRUE) {
 
     $language_manager = \Drupal::languageManager();
     $language_manager->reset();
-    if ($language_manager instanceof ConfigurableLanguageManagerInterface) {
+    if (!$this->isLocked() && $language_manager instanceof ConfigurableLanguageManagerInterface) {
       $language_manager->updateLockedLanguageWeights();
     }
 
@@ -230,6 +230,14 @@ public function getWeight() {
     return $this->weight;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function setWeight($weight) {
+    $this->weight = $weight;
+    return $this;
+  }
+
   /**
    * Creates a configurable language object from a langcode.
    *
diff --git a/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
index 64f199306a86..1dc1447522de 100644
--- a/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserDeleteForm.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\language\Form;
 
+use Drupal\Core\Form\ConfigFormBaseTrait;
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Url;
@@ -16,6 +17,7 @@
  * Defines a confirmation form for deleting a browser language negotiation mapping.
  */
 class NegotiationBrowserDeleteForm extends ConfirmFormBase {
+  use ConfigFormBaseTrait;
 
   /**
    * The browser language code to be deleted.
@@ -24,6 +26,14 @@ class NegotiationBrowserDeleteForm extends ConfirmFormBase {
    */
   protected $browserLangcode;
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['language.mappings'];
+  }
+
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/src/Form/NegotiationBrowserForm.php b/core/modules/language/src/Form/NegotiationBrowserForm.php
index d7722141f317..14ebb625985f 100644
--- a/core/modules/language/src/Form/NegotiationBrowserForm.php
+++ b/core/modules/language/src/Form/NegotiationBrowserForm.php
@@ -53,6 +53,13 @@ public function getFormId() {
     return 'language_negotiation_configure_browser_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['language.mappings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/src/Form/NegotiationConfigureForm.php b/core/modules/language/src/Form/NegotiationConfigureForm.php
index ca208018fd5d..d9cf42051aa6 100644
--- a/core/modules/language/src/Form/NegotiationConfigureForm.php
+++ b/core/modules/language/src/Form/NegotiationConfigureForm.php
@@ -118,6 +118,13 @@ public function getFormID() {
     return 'language_negotiation_configure_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['language.types'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/src/Form/NegotiationSelectedForm.php b/core/modules/language/src/Form/NegotiationSelectedForm.php
index 5b5d5a978371..57194f96fd08 100644
--- a/core/modules/language/src/Form/NegotiationSelectedForm.php
+++ b/core/modules/language/src/Form/NegotiationSelectedForm.php
@@ -23,6 +23,13 @@ public function getFormId() {
     return 'language_negotiation_configure_selected_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['language.negotiation'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/src/Form/NegotiationSessionForm.php b/core/modules/language/src/Form/NegotiationSessionForm.php
index a0bd7779c9f2..fff1dd59902c 100644
--- a/core/modules/language/src/Form/NegotiationSessionForm.php
+++ b/core/modules/language/src/Form/NegotiationSessionForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'language_negotiation_configure_session_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['language.negotiation'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/src/Form/NegotiationUrlForm.php b/core/modules/language/src/Form/NegotiationUrlForm.php
index 979cca9038f4..fa1cd3eada7f 100644
--- a/core/modules/language/src/Form/NegotiationUrlForm.php
+++ b/core/modules/language/src/Form/NegotiationUrlForm.php
@@ -56,6 +56,13 @@ public function getFormId() {
     return 'language_negotiation_configure_url_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['language.negotiation'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/language/src/LanguageNegotiator.php b/core/modules/language/src/LanguageNegotiator.php
index af2d9529c4e7..bc924fbf2a50 100644
--- a/core/modules/language/src/LanguageNegotiator.php
+++ b/core/modules/language/src/LanguageNegotiator.php
@@ -286,7 +286,7 @@ function saveConfiguration($type, $enabled_methods) {
         unset($enabled_methods[$method_id]);
       }
     }
-    $this->configFactory->get('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save();
+    $this->configFactory->getEditable('language.types')->set('negotiation.' . $type . '.enabled', $enabled_methods)->save();
   }
 
   /**
diff --git a/core/modules/language/tests/language_test/language_test.module b/core/modules/language/tests/language_test/language_test.module
index 0a891982ada1..2ca1ff5eafac 100644
--- a/core/modules/language/tests/language_test/language_test.module
+++ b/core/modules/language/tests/language_test/language_test.module
@@ -45,10 +45,11 @@ function language_test_language_types_info_alter(array &$language_types) {
     unset($language_types[LanguageInterface::TYPE_CONTENT]['fixed']);
     // By default languages are not configurable. Make
     // LanguageInterface::TYPE_CONTENT configurable.
-    $configurable = \Drupal::config('language.types')->get('configurable');
+    $config = \Drupal::configFactory()->getEditable('language.types');
+    $configurable = $config->get('configurable');
     if (!in_array(LanguageInterface::TYPE_CONTENT, $configurable)) {
       $configurable[] = LanguageInterface::TYPE_CONTENT;
-      \Drupal::config('language.types')->set('configurable', $configurable)->save();
+      $config->set('configurable', $configurable)->save();
     }
   }
 }
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 8aa8d82370f4..81aadf534b4e 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -16,7 +16,7 @@ function locale_install() {
   // Create the interface translations directory and ensure it's writable.
   if (!$directory = \Drupal::config('locale.settings')->get('translation.path')) {
     $directory = conf_path() . '/files/translations';
-    \Drupal::config('locale.settings')->set('translation.path', $directory)->save();
+    \Drupal::configFactory()->getEditable('locale.settings')->set('translation.path', $directory)->save();
   }
   file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
 }
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 9e09a4636fea..52a5eb9e2dca 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -647,7 +647,7 @@ function locale_form_language_admin_edit_form_alter(&$form, FormStateInterface $
     $form['locale_translate_english'] = array(
       '#title' => t('Enable interface translation to English'),
       '#type' => 'checkbox',
-      '#default_value' => locale_translate_english(),
+      '#default_value' => \Drupal::configFactory()->getEditable('locale.settings')->get('translate_english'),
     );
     $form['actions']['submit']['#submit'][] = 'locale_form_language_admin_edit_form_alter_submit';
   }
@@ -657,7 +657,7 @@ function locale_form_language_admin_edit_form_alter(&$form, FormStateInterface $
  * Form submission handler for language_admin_edit_form().
  */
 function locale_form_language_admin_edit_form_alter_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('locale.settings')->set('translate_english', intval($form_state->getValue('locale_translate_english')))->save();
+  \Drupal::configFactory()->getEditable('locale.settings')->set('translate_english', intval($form_state->getValue('locale_translate_english')))->save();
 }
 
 /**
diff --git a/core/modules/locale/src/Form/LocaleSettingsForm.php b/core/modules/locale/src/Form/LocaleSettingsForm.php
index 16c2087c27ee..4ff2c3332453 100644
--- a/core/modules/locale/src/Form/LocaleSettingsForm.php
+++ b/core/modules/locale/src/Form/LocaleSettingsForm.php
@@ -21,6 +21,13 @@ public function getFormId() {
     return 'locale_translate_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['locale.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/locale/src/Tests/LocaleUpdateBase.php b/core/modules/locale/src/Tests/LocaleUpdateBase.php
index 4a92a3051752..7e17c892e152 100644
--- a/core/modules/locale/src/Tests/LocaleUpdateBase.php
+++ b/core/modules/locale/src/Tests/LocaleUpdateBase.php
@@ -60,7 +60,7 @@ protected function setUp() {
     // Update module should not go out to d.o to check for updates. We override
     // the url to the default update_test xml path. But without providing
     // a mock xml file, no update data will be found.
-    \Drupal::config('update.settings')->set('fetch.url', _url('update-test', array('absolute' => TRUE)))->save();
+    $this->config('update.settings')->set('fetch.url', _url('update-test', array('absolute' => TRUE)))->save();
 
     // Setup timestamps to identify old and new translation sources.
     $this->timestampOld = REQUEST_TIME - 300;
@@ -70,7 +70,7 @@ protected function setUp() {
 
     // Enable import of translations. By default this is disabled for automated
     // tests.
-    \Drupal::config('locale.settings')
+    $this->config('locale.settings')
       ->set('translation.import_enabled', TRUE)
       ->save();
   }
@@ -84,7 +84,7 @@ protected function setUp() {
    */
   protected function setTranslationsDirectory($path) {
     file_prepare_directory($path, FILE_CREATE_DIRECTORY);
-    \Drupal::config('locale.settings')->set('translation.path', $path)->save();
+    $this->config('locale.settings')->set('translation.path', $path)->save();
   }
 
   /**
@@ -180,7 +180,7 @@ protected function makePoFile($path, $filename, $timestamp = NULL, array $transl
    * imported.
    */
   protected function setTranslationFiles() {
-    $config = \Drupal::config('locale.settings');
+    $config = $this->config('locale.settings');
 
     // A flag is set to let the locale_test module replace the project data with
     // a set of test projects which match the below project files.
diff --git a/core/modules/migrate/src/Plugin/migrate/destination/Config.php b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
index a7b5de29d3e6..7d84813a6c1d 100644
--- a/core/modules/migrate/src/Plugin/migrate/destination/Config.php
+++ b/core/modules/migrate/src/Plugin/migrate/destination/Config.php
@@ -6,6 +6,7 @@
 
 namespace Drupal\migrate\Plugin\migrate\destination;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\migrate\Entity\MigrationInterface;
 use Drupal\migrate\MigrateException;
@@ -43,12 +44,12 @@ class Config extends DestinationBase implements ContainerFactoryPluginInterface
    *   The plugin implementation definition.
    * @param \Drupal\migrate\Entity\MigrationInterface $migration
    *   The migration entity.
-   * @param \Drupal\Core\Config\Config $config
-   *   The configuration object.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The configuration factory.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, ConfigObject $config) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration, ConfigFactoryInterface $config_factory) {
     parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
-    $this->config = $config;
+    $this->config = $config_factory->getEditable($configuration['config_name']);
   }
 
   /**
@@ -60,7 +61,7 @@ public static function create(ContainerInterface $container, array $configuratio
       $plugin_id,
       $plugin_definition,
       $migration,
-      $container->get('config.factory')->get($configuration['config_name'])
+      $container->get('config.factory')
     );
   }
 
diff --git a/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php b/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
index 8ed3f6d846ea..6b7dcd7cbeb5 100644
--- a/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
+++ b/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
@@ -37,13 +37,18 @@ public function testImport() {
     }
     $config->expects($this->once())
       ->method('save');
+    $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
+    $config_factory->expects($this->once())
+      ->method('getEditable')
+      ->with('d8_config')
+      ->will($this->returnValue($config));
     $row = $this->getMockBuilder('Drupal\migrate\Row')
       ->disableOriginalConstructor()
       ->getMock();
     $row->expects($this->once())
       ->method('getRawDestination')
       ->will($this->returnValue($source));
-    $destination = new Config(array(), 'd8_config', array('pluginId' => 'd8_config'), $migration, $config);
+    $destination = new Config(array('config_name' => 'd8_config'), 'd8_config', array('pluginId' => 'd8_config'), $migration, $config_factory);
     $destination->import($row);
   }
 
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index a82ba2e65b7b..a1f2c3b4e685 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -843,7 +843,7 @@ function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $fo
   $form['admin_theme']['use_admin_theme'] = array(
     '#type' => 'checkbox',
     '#title' => t('Use the administration theme when editing or creating content'),
-    '#default_value' => \Drupal::config('node.settings')->get('use_admin_theme'),
+    '#default_value' => \Drupal::configFactory()->getEditable('node.settings')->get('use_admin_theme'),
   );
   $form['#submit'][] = 'node_form_system_themes_admin_form_submit';
 }
@@ -854,7 +854,7 @@ function node_form_system_themes_admin_form_alter(&$form, FormStateInterface $fo
  * @see node_form_system_themes_admin_form_alter()
  */
 function node_form_system_themes_admin_form_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('node.settings')
+  \Drupal::configFactory()->getEditable('node.settings')
     ->set('use_admin_theme', $form_state->getValue('use_admin_theme'))
     ->save();
   \Drupal::service('router.builder_indicator')->setRebuildNeeded();
diff --git a/core/modules/search/src/SearchPageListBuilder.php b/core/modules/search/src/SearchPageListBuilder.php
index 9efd4cce5063..62aa99ea00f6 100644
--- a/core/modules/search/src/SearchPageListBuilder.php
+++ b/core/modules/search/src/SearchPageListBuilder.php
@@ -328,7 +328,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
-    $search_settings = $this->configFactory->get('search.settings');
+    $search_settings = $this->configFactory->getEditable('search.settings');
     // If these settings change, the default index needs to be rebuilt.
     if (($search_settings->get('index.minimum_word_size') != $form_state->getValue('minimum_word_size')) || ($search_settings->get('index.overlap_cjk') != $form_state->getValue('overlap_cjk'))) {
       $search_settings->set('index.minimum_word_size', $form_state->getValue('minimum_word_size'));
diff --git a/core/modules/search/src/SearchPageRepository.php b/core/modules/search/src/SearchPageRepository.php
index 3dfdfb237b2b..66f7bdadaf40 100644
--- a/core/modules/search/src/SearchPageRepository.php
+++ b/core/modules/search/src/SearchPageRepository.php
@@ -94,14 +94,14 @@ public function getDefaultSearchPage() {
    * {@inheritdoc}
    */
   public function clearDefaultSearchPage() {
-    $this->configFactory->get('search.settings')->clear('default_page')->save();
+    $this->configFactory->getEditable('search.settings')->clear('default_page')->save();
   }
 
   /**
    * {@inheritdoc}
    */
   public function setDefaultSearchPage(SearchPageInterface $search_page) {
-    $this->configFactory->get('search.settings')->set('default_page', $search_page->id())->save();
+    $this->configFactory->getEditable('search.settings')->set('default_page', $search_page->id())->save();
     $search_page->enable()->save();
   }
 
diff --git a/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php b/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php
index 3ff112e04bc2..767a81b59a3c 100644
--- a/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php
+++ b/core/modules/search/tests/src/Unit/SearchPageRepositoryTest.php
@@ -151,7 +151,7 @@ public function testClearDefaultSearchPage() {
       ->with('default_page')
       ->will($this->returnValue($config));
     $this->configFactory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->with('search.settings')
       ->will($this->returnValue($config));
     $this->searchPageRepository->clearDefaultSearchPage();
@@ -227,7 +227,7 @@ public function testSetDefaultSearchPage() {
       ->method('save')
       ->will($this->returnValue($config));
     $this->configFactory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->with('search.settings')
       ->will($this->returnValue($config));
 
diff --git a/core/modules/shortcut/shortcut.install b/core/modules/shortcut/shortcut.install
index d716a0395ae0..41a78a2afdf0 100644
--- a/core/modules/shortcut/shortcut.install
+++ b/core/modules/shortcut/shortcut.install
@@ -56,7 +56,7 @@ function shortcut_install() {
   // Theme settings are not configuration entities and cannot depend on modules
   // so to set a module-specific setting, we need to set it with logic.
   if (\Drupal::service('theme_handler')->themeExists('seven')) {
-    \Drupal::config('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
+    \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
   }
 }
 
@@ -67,6 +67,6 @@ function shortcut_uninstall() {
   // Theme settings are not configuration entities and cannot depend on modules
   // so to unset a module-specific setting, we need to unset it with logic.
   if (\Drupal::service('theme_handler')->themeExists('seven')) {
-    \Drupal::config('seven.settings')->clear('third_party_settings.shortcut.module_link')->save();
+    \Drupal::configFactory()->getEditable('seven.settings')->clear('third_party_settings.shortcut.module_link')->save();
   }
 }
diff --git a/core/modules/shortcut/shortcut.module b/core/modules/shortcut/shortcut.module
index ba9c43db0055..88c64dd0af9d 100644
--- a/core/modules/shortcut/shortcut.module
+++ b/core/modules/shortcut/shortcut.module
@@ -405,7 +405,7 @@ function shortcut_themes_installed($theme_list) {
     // Theme settings are not configuration entities and cannot depend on modules
     // so to set a module-specific setting, we need to set it with logic.
     if (\Drupal::moduleHandler()->moduleExists('shortcut')) {
-      \Drupal::config('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
+      \Drupal::configFactory()->getEditable('seven.settings')->set('third_party_settings.shortcut.module_link', TRUE)->save();
     }
   }
 }
diff --git a/core/modules/simpletest/src/Form/SimpletestSettingsForm.php b/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
index d4e719773b69..e6d4d4df1e11 100644
--- a/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
+++ b/core/modules/simpletest/src/Form/SimpletestSettingsForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'simpletest_settings_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['simpletest.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/simpletest/src/InstallerTestBase.php b/core/modules/simpletest/src/InstallerTestBase.php
index d87718e303df..11e9076cb5dc 100644
--- a/core/modules/simpletest/src/InstallerTestBase.php
+++ b/core/modules/simpletest/src/InstallerTestBase.php
@@ -160,7 +160,7 @@ protected function setUp() {
 
     // Manually configure the test mail collector implementation to prevent
     // tests from sending out e-mails and collect them in state instead.
-    $config->get('system.mail')
+    $config->getEditable('system.mail')
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
diff --git a/core/modules/simpletest/src/KernelTestBase.php b/core/modules/simpletest/src/KernelTestBase.php
index 50e96b4f4861..e5d076aca4db 100644
--- a/core/modules/simpletest/src/KernelTestBase.php
+++ b/core/modules/simpletest/src/KernelTestBase.php
@@ -208,7 +208,10 @@ protected function setUp() {
     if ($modules) {
       $this->enableModules($modules);
     }
-    // In order to use theme functions default theme config needs to exist.
+    // In order to use theme functions default theme config needs to exist. This
+    // configuration is not saved because it would fatal due to system module's
+    // configuration schema not existing. However since the configuration is
+    // cached in the configuration factory everything works.
     $this->config('system.theme')->set('default', 'classy');
 
     // Tests based on this class are entitled to use Drupal's File and
@@ -483,7 +486,7 @@ protected function disableModules(array $modules) {
     // Unset the list of modules in the extension handler.
     $module_handler = $this->container->get('module_handler');
     $module_filenames = $module_handler->getModuleList();
-    $extension_config = $this->container->get('config.factory')->get('core.extension');
+    $extension_config = $this->config('core.extension');
     foreach ($modules as $module) {
       unset($module_filenames[$module]);
       $extension_config->clear('module.' . $module);
diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php
index 7eaf71bbd605..cfcfdbc56801 100644
--- a/core/modules/simpletest/src/TestBase.php
+++ b/core/modules/simpletest/src/TestBase.php
@@ -1629,7 +1629,7 @@ protected function config($name) {
     $config_factory = \Drupal::configFactory();
     $old_state = $config_factory->getOverrideState();
     $config_factory->setOverrideState(FALSE);
-    $config = $config_factory->get($name);
+    $config = $config_factory->getEditable($name);
     $config_factory->setOverrideState($old_state);
     return $config;
   }
diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php
index bb6401fed51d..8b042afd78c3 100644
--- a/core/modules/simpletest/src/WebTestBase.php
+++ b/core/modules/simpletest/src/WebTestBase.php
@@ -888,7 +888,7 @@ protected function setUp() {
     // UI. If declared in settings.php, they would no longer be configurable.
     file_prepare_directory($this->privateFilesDirectory, FILE_CREATE_DIRECTORY);
     file_prepare_directory($this->tempFilesDirectory, FILE_CREATE_DIRECTORY);
-    $config->get('system.file')
+    $config->getEditable('system.file')
       ->set('path.temporary', $this->tempFilesDirectory)
       ->save();
 
@@ -896,7 +896,7 @@ protected function setUp() {
     // tests from sending out emails and collect them in state instead.
     // While this should be enforced via settings.php prior to installation,
     // some tests expect to be able to test mail system implementations.
-    $config->get('system.mail')
+    $config->getEditable('system.mail')
       ->set('interface.default', 'test_mail_collector')
       ->save();
 
@@ -904,10 +904,10 @@ protected function setUp() {
     // environment optimizations for all tests to avoid needless overhead and
     // ensure a sane default experience for test authors.
     // @see https://drupal.org/node/2259167
-    $config->get('system.logging')
+    $config->getEditable('system.logging')
       ->set('error_level', 'verbose')
       ->save();
-    $config->get('system.performance')
+    $config->getEditable('system.performance')
       ->set('css.preprocess', FALSE)
       ->set('js.preprocess', FALSE)
       ->save();
diff --git a/core/modules/statistics/src/StatisticsSettingsForm.php b/core/modules/statistics/src/StatisticsSettingsForm.php
index 47411d7b38f1..2213befda3c5 100644
--- a/core/modules/statistics/src/StatisticsSettingsForm.php
+++ b/core/modules/statistics/src/StatisticsSettingsForm.php
@@ -55,6 +55,13 @@ public function getFormId() {
     return 'statistics_settings_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['statistics.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/syslog/syslog.install b/core/modules/syslog/syslog.install
index 8a2350a78fc1..e3377c8aeb74 100644
--- a/core/modules/syslog/syslog.install
+++ b/core/modules/syslog/syslog.install
@@ -11,5 +11,5 @@
 function syslog_install() {
   // The default facility setting depends on the operating system, so it needs
   // to be set dynamically during installation.
-  \Drupal::config('syslog.settings')->set('facility', defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER)->save();
+  \Drupal::configFactory()->getEditable('syslog.settings')->set('facility', defined('LOG_LOCAL0') ? LOG_LOCAL0 : LOG_USER)->save();
 }
diff --git a/core/modules/syslog/syslog.module b/core/modules/syslog/syslog.module
index aad40609a84f..61873f981171 100644
--- a/core/modules/syslog/syslog.module
+++ b/core/modules/syslog/syslog.module
@@ -33,7 +33,7 @@ function syslog_help($route_name, RouteMatchInterface $route_match) {
  * Implements hook_form_FORM_ID_alter().
  */
 function syslog_form_system_logging_settings_alter(&$form, FormStateInterface $form_state) {
-  $config = \Drupal::config('syslog.settings');
+  $config = \Drupal::configFactory()->getEditable('syslog.settings');
   $help = \Drupal::moduleHandler()->moduleExists('help') ? ' ' . \Drupal::l(t('More information'), new Url('help.page', ['name' => 'syslog'])) . '.' : NULL;
   $form['syslog_identity'] = array(
     '#type'          => 'textfield',
@@ -66,7 +66,7 @@ function syslog_form_system_logging_settings_alter(&$form, FormStateInterface $f
  * @see syslog_form_system_logging_settings_alter()
  */
 function syslog_logging_settings_submit($form, FormStateInterface $form_state) {
-  \Drupal::config('syslog.settings')
+  \Drupal::configFactory()->getEditable('syslog.settings')
     ->set('identity', $form_state->getValue('syslog_identity'))
     ->set('facility', $form_state->getValue('syslog_facility'))
     ->set('format', $form_state->getValue('syslog_format'))
diff --git a/core/modules/system/src/Controller/ThemeController.php b/core/modules/system/src/Controller/ThemeController.php
index 3bb6d316895b..26083cbf4657 100644
--- a/core/modules/system/src/Controller/ThemeController.php
+++ b/core/modules/system/src/Controller/ThemeController.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\system\Controller;
 
+use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Extension\ThemeHandlerInterface;
 use Drupal\Core\Routing\RouteBuilderIndicatorInterface;
@@ -40,10 +41,13 @@ class ThemeController extends ControllerBase {
    *   The theme handler.
    * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder_indicator
    *   The route builder.
+   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
+   *   The config factory.
    */
-  public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderIndicatorInterface $route_builder_indicator) {
+  public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderIndicatorInterface $route_builder_indicator, ConfigFactoryInterface $config_factory) {
     $this->themeHandler = $theme_handler;
     $this->routeBuilderIndicator = $route_builder_indicator;
+    $this->configFactory = $config_factory;
   }
 
   /**
@@ -52,7 +56,8 @@ public function __construct(ThemeHandlerInterface $theme_handler, RouteBuilderIn
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('theme_handler'),
-      $container->get('router.builder_indicator')
+      $container->get('router.builder_indicator'),
+      $container->get('config.factory')
     );
   }
 
@@ -142,7 +147,7 @@ public function install(Request $request) {
    *   Throws access denied when no theme is set in the request.
    */
   public function setDefaultTheme(Request $request) {
-    $config = $this->config('system.theme');
+    $config = $this->configFactory->getEditable('system.theme');
     $theme = $request->query->get('theme');
 
     if (isset($theme)) {
diff --git a/core/modules/system/src/Form/CronForm.php b/core/modules/system/src/Form/CronForm.php
index cfb82fd8857e..f906c7022358 100644
--- a/core/modules/system/src/Form/CronForm.php
+++ b/core/modules/system/src/Form/CronForm.php
@@ -80,6 +80,13 @@ public function getFormId() {
     return 'system_cron_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.cron'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/FileSystemForm.php b/core/modules/system/src/Form/FileSystemForm.php
index 8cf5eb38fdec..368f318d08b4 100644
--- a/core/modules/system/src/Form/FileSystemForm.php
+++ b/core/modules/system/src/Form/FileSystemForm.php
@@ -71,6 +71,13 @@ public function getFormId() {
     return 'system_file_system_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.file'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/ImageToolkitForm.php b/core/modules/system/src/Form/ImageToolkitForm.php
index 6eeaa4ef942c..0d9bec9446ea 100644
--- a/core/modules/system/src/Form/ImageToolkitForm.php
+++ b/core/modules/system/src/Form/ImageToolkitForm.php
@@ -58,6 +58,13 @@ public function getFormId() {
     return 'system_image_toolkit_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.image'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/LoggingForm.php b/core/modules/system/src/Form/LoggingForm.php
index 500fed033ab3..cfbbddc46a78 100644
--- a/core/modules/system/src/Form/LoggingForm.php
+++ b/core/modules/system/src/Form/LoggingForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'system_logging_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.logging'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/PerformanceForm.php b/core/modules/system/src/Form/PerformanceForm.php
index 372b319e321b..9049c7825bb2 100644
--- a/core/modules/system/src/Form/PerformanceForm.php
+++ b/core/modules/system/src/Form/PerformanceForm.php
@@ -90,6 +90,13 @@ public function getFormId() {
     return 'system_performance_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.performance'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/RegionalForm.php b/core/modules/system/src/Form/RegionalForm.php
index 2d3934f27813..827f74f7fa34 100644
--- a/core/modules/system/src/Form/RegionalForm.php
+++ b/core/modules/system/src/Form/RegionalForm.php
@@ -55,6 +55,13 @@ public function getFormId() {
     return 'system_regional_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.date'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/RssFeedsForm.php b/core/modules/system/src/Form/RssFeedsForm.php
index 84f18fa7929c..cde99641440e 100644
--- a/core/modules/system/src/Form/RssFeedsForm.php
+++ b/core/modules/system/src/Form/RssFeedsForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'system_rss_feeds_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.rss'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/SiteInformationForm.php b/core/modules/system/src/Form/SiteInformationForm.php
index f2efcd513315..71a0fbd2d9de 100644
--- a/core/modules/system/src/Form/SiteInformationForm.php
+++ b/core/modules/system/src/Form/SiteInformationForm.php
@@ -68,6 +68,13 @@ public function getFormId() {
     return 'system_site_information_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.site'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/SiteMaintenanceModeForm.php b/core/modules/system/src/Form/SiteMaintenanceModeForm.php
index b87533e2ec76..cde1f57fd4f8 100644
--- a/core/modules/system/src/Form/SiteMaintenanceModeForm.php
+++ b/core/modules/system/src/Form/SiteMaintenanceModeForm.php
@@ -54,6 +54,13 @@ public function getFormId() {
     return 'system_site_maintenance_mode';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.maintenance'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/ThemeAdminForm.php b/core/modules/system/src/Form/ThemeAdminForm.php
index 93cace87f425..9aa712379cb8 100644
--- a/core/modules/system/src/Form/ThemeAdminForm.php
+++ b/core/modules/system/src/Form/ThemeAdminForm.php
@@ -21,6 +21,13 @@ public function getFormID() {
     return 'system_themes_admin_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['system.theme'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/src/Form/ThemeSettingsForm.php b/core/modules/system/src/Form/ThemeSettingsForm.php
index 959fd565be13..75983f07c3e7 100644
--- a/core/modules/system/src/Form/ThemeSettingsForm.php
+++ b/core/modules/system/src/Form/ThemeSettingsForm.php
@@ -37,6 +37,13 @@ class ThemeSettingsForm extends ConfigFormBase {
    */
   protected $themeHandler;
 
+  /**
+   * An array of configuration names that should be editable.
+   *
+   * @var array
+   */
+  protected $editableConfig = [];
+
   /**
    * Constructs a ThemeSettingsForm object.
    *
@@ -72,6 +79,13 @@ public function getFormId() {
     return 'system_theme_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return $this->editableConfig;
+  }
+
   /**
    * {@inheritdoc}
    *
@@ -99,6 +113,10 @@ public function buildForm(array $form, FormStateInterface $form_state, $theme =
       $var = 'theme_settings';
       $config_key = 'system.theme.global';
     }
+    // @todo this is pretty meaningless since we're using theme_get_settings
+    //   which means overrides can bleed into active config here. Will be fixed
+    //   by https://www.drupal.org/node/2402467.
+    $this->editableConfig = [$config_key];
 
     $form['var'] = array(
       '#type' => 'hidden',
@@ -389,7 +407,9 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     parent::submitForm($form, $form_state);
 
-    $config = $this->config($form_state->getValue('config_key'));
+    $config_key = $form_state->getValue('config_key');
+    $this->editableConfig = [$config_key];
+    $config = $this->config($config_key);
 
     // Exclude unnecessary elements before saving.
     $form_state->cleanValues();
diff --git a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
index 7aa56d03eafe..d16330f62a53 100644
--- a/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
+++ b/core/modules/system/src/Plugin/ImageToolkit/GDToolkit.php
@@ -104,7 +104,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       '#description' => t('Define the image quality for JPEG manipulations. Ranges from 0 to 100. Higher values mean better image quality but bigger files.'),
       '#min' => 0,
       '#max' => 100,
-      '#default_value' => $this->configFactory->get('system.image.gd')->get('jpeg_quality'),
+      '#default_value' => $this->configFactory->getEditable('system.image.gd')->get('jpeg_quality', FALSE),
       '#field_suffix' => t('%'),
     );
     return $form;
@@ -114,7 +114,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
    * {@inheritdoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configFactory->get('system.image.gd')
+    $this->configFactory->getEditable('system.image.gd')
       ->set('jpeg_quality', $form_state->getValue(array('gd', 'image_jpeg_quality')))
       ->save();
   }
diff --git a/core/modules/system/src/Tests/Form/FormObjectTest.php b/core/modules/system/src/Tests/Form/FormObjectTest.php
index 237d9e74a4af..a732e9678da4 100644
--- a/core/modules/system/src/Tests/Form/FormObjectTest.php
+++ b/core/modules/system/src/Tests/Form/FormObjectTest.php
@@ -27,7 +27,7 @@ class FormObjectTest extends SystemConfigFormTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $this->form = new FormTestObject();
+    $this->form = new FormTestObject($this->container->get('config.factory'));
     $this->values = array(
       'bananas' => array(
         '#value' => $this->randomString(10),
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index cc2079fa6961..08e7865983fd 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -623,7 +623,7 @@ function system_install() {
   \Drupal::state()->set('system.cron_key', $cron_key);
 
   // Populate the site UUID.
-  \Drupal::config('system.site')
+  \Drupal::configFactory()->getEditable('system.site')
     ->set('uuid', \Drupal::service('uuid')->generate())
     ->save();
 }
diff --git a/core/modules/system/tests/modules/form_test/form_test.services.yml b/core/modules/system/tests/modules/form_test/form_test.services.yml
index 472e0bc03877..24513a66e0e6 100644
--- a/core/modules/system/tests/modules/form_test/form_test.services.yml
+++ b/core/modules/system/tests/modules/form_test/form_test.services.yml
@@ -1,6 +1,7 @@
 services:
   form_test.form.serviceform:
     class: Drupal\form_test\FormTestServiceObject
+    arguments: ['@config.factory']
   form_test.event_subscriber:
     class: Drupal\form_test\EventSubscriber\FormTestEventSubscriber
     tags:
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php b/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
index da7b4d58330c..9dc522ce762d 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestArgumentsObject.php
@@ -8,13 +8,13 @@
 namespace Drupal\form_test;
 
 use Drupal\Component\Utility\String;
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object that needs arguments.
  */
-class FormTestArgumentsObject extends FormBase {
+class FormTestArgumentsObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -23,6 +23,13 @@ public function getFormId() {
     return 'form_test_form_test_arguments_object';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
index 1b96b3da093d..40a79af1fb4a 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\form_test;
 
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -15,7 +15,7 @@
 /**
  * Provides a test form object.
  */
-class FormTestControllerObject extends FormBase {
+class FormTestControllerObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -24,12 +24,21 @@ public function getFormId() {
     return 'form_test_form_test_controller_object';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
   /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container) {
     drupal_set_message(t('The FormTestControllerObject::create() method was used for this form.'));
-    return new static();
+    return new static(
+      $container->get('config.factory')
+    );
   }
 
   /**
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestObject.php b/core/modules/system/tests/modules/form_test/src/FormTestObject.php
index 4669bfec6519..73f273e6fb09 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestObject.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\form_test;
 
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object.
  */
-class FormTestObject extends FormBase {
+class FormTestObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'form_test_form_test_object';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php b/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
index de4e6c0fdcdb..c60b6d158d62 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestServiceObject.php
@@ -7,13 +7,13 @@
 
 namespace Drupal\form_test;
 
-use Drupal\Core\Form\FormBase;
+use Drupal\Core\Form\ConfigFormBase;
 use Drupal\Core\Form\FormStateInterface;
 
 /**
  * Provides a test form object.
  */
-class FormTestServiceObject extends FormBase {
+class FormTestServiceObject extends ConfigFormBase {
 
   /**
    * {@inheritdoc}
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'form_test_form_test_service_object';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['form_test.object'];
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -54,7 +61,7 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
    */
   public function submitForm(array &$form, FormStateInterface $form_state) {
     drupal_set_message($this->t('The FormTestServiceObject::submitForm() method was used for this form.'));
-    $this->config('form_test.object')
+    $this->config('form_test.object', FALSE)
       ->set('bananas', $form_state->getValue('bananas'))
       ->save();
   }
diff --git a/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php b/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php
index 45efda74babd..243a81b10390 100644
--- a/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php
+++ b/core/modules/system/tests/modules/form_test/src/SystemConfigFormTestForm.php
@@ -21,4 +21,11 @@ public function getFormId() {
     return 'form_test_system_config_test_form';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return [];
+  }
+
 }
diff --git a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
index f72eaaaddd10..7513ac26f9c4 100644
--- a/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
+++ b/core/modules/system/tests/modules/image_test/src/Plugin/ImageToolkit/TestToolkit.php
@@ -103,7 +103,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
       '#description' => $this->t('A toolkit parameter for testing purposes.'),
       '#min' => 0,
       '#max' => 100,
-      '#default_value' => $this->configFactory->get('system.image.test_toolkit')->get('test_parameter'),
+      '#default_value' => $this->configFactory->getEditable('system.image.test_toolkit')->get('test_parameter', FALSE),
     );
     return $form;
   }
@@ -121,7 +121,7 @@ public function validateConfigurationForm(array &$form, FormStateInterface $form
    * {@inheritdoc}
    */
   public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
-    $this->configFactory->get('system.image.test_toolkit')
+    $this->configFactory->getEditable('system.image.test_toolkit')
       ->set('test_parameter', $form_state->getValue(array('test', 'test_parameter')))
       ->save();
   }
diff --git a/core/modules/update/src/UpdateSettingsForm.php b/core/modules/update/src/UpdateSettingsForm.php
index 81ef7e00930b..7e4664de9d2d 100644
--- a/core/modules/update/src/UpdateSettingsForm.php
+++ b/core/modules/update/src/UpdateSettingsForm.php
@@ -22,6 +22,13 @@ public function getFormId() {
     return 'update_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['update.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/user/src/AccountSettingsForm.php b/core/modules/user/src/AccountSettingsForm.php
index bce6a6064f7e..2b91877d9b03 100644
--- a/core/modules/user/src/AccountSettingsForm.php
+++ b/core/modules/user/src/AccountSettingsForm.php
@@ -56,6 +56,17 @@ public function getFormId() {
     return 'user_admin_settings';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return [
+      'system.site',
+      'user.mail',
+      'user.settings',
+    ];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 38f0ba06ba75..ed18d47b77b0 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1369,7 +1369,7 @@ function user_modules_uninstalled($modules) {
   \Drupal::service('user.data')->delete($modules);
   // User signatures require Filter module.
   if (in_array('filter', $modules)) {
-    \Drupal::config('user.settings')->set('signatures', FALSE)->save();
+    \Drupal::configFactory()->getEditable('user.settings')->set('signatures', FALSE)->save();
   }
 }
 
diff --git a/core/modules/views/tests/modules/views_test_data/views_test_data.install b/core/modules/views/tests/modules/views_test_data/views_test_data.install
index 8cd7f38a3c33..eeb5faa845cc 100644
--- a/core/modules/views/tests/modules/views_test_data/views_test_data.install
+++ b/core/modules/views/tests/modules/views_test_data/views_test_data.install
@@ -31,5 +31,5 @@ function views_test_data_install() {
     'em' => 'EM',
     'marquee' => 'MARQUEE'
   );
-  \Drupal::config('views.settings')->set('field_rewrite_elements', $values)->save();
+  \Drupal::configFactory()->getEditable('views.settings')->set('field_rewrite_elements', $values)->save();
 }
diff --git a/core/modules/views_ui/src/Form/AdvancedSettingsForm.php b/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
index a9ffd6f0081d..d8cd1e21d42a 100644
--- a/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
+++ b/core/modules/views_ui/src/Form/AdvancedSettingsForm.php
@@ -23,6 +23,13 @@ public function getFormId() {
     return 'views_ui_admin_settings_advanced';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['views.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/modules/views_ui/src/Form/BasicSettingsForm.php b/core/modules/views_ui/src/Form/BasicSettingsForm.php
index 557745b50302..1732c9ac0fd9 100644
--- a/core/modules/views_ui/src/Form/BasicSettingsForm.php
+++ b/core/modules/views_ui/src/Form/BasicSettingsForm.php
@@ -56,6 +56,13 @@ public function getFormId() {
     return 'views_ui_admin_settings_basic';
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function getEditableConfigNames() {
+    return ['views.settings'];
+  }
+
   /**
    * {@inheritdoc}
    */
diff --git a/core/profiles/minimal/minimal.install b/core/profiles/minimal/minimal.install
index 52bea389a499..a8baf07906b3 100644
--- a/core/profiles/minimal/minimal.install
+++ b/core/profiles/minimal/minimal.install
@@ -13,8 +13,8 @@
  */
 function minimal_install() {
   // Disable the user pictures on nodes.
-  \Drupal::config('system.theme.global')->set('features.node_user_picture', FALSE)->save();
+  \Drupal::configFactory()->getEditable('system.theme.global')->set('features.node_user_picture', FALSE)->save();
 
   // Allow visitor account creation, but with administrative approval.
-  \Drupal::config('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
+  \Drupal::configFactory()->getEditable('user.settings')->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
 }
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index 645587b3babd..f57166793f5b 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -22,10 +22,10 @@ function standard_install() {
   \Drupal::service('entity.definition_update_manager')->applyUpdates();
 
   // Set front page to "node".
-  \Drupal::config('system.site')->set('page.front', 'node')->save();
+  \Drupal::configFactory()->getEditable('system.site')->set('page.front', 'node')->save();
 
   // Allow visitor account creation with administrative approval.
-  $user_settings = \Drupal::config('user.settings');
+  $user_settings = \Drupal::configFactory()->getEditable('user.settings');
   $user_settings->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
 
   // Enable default permissions for system roles.
@@ -71,5 +71,5 @@ function standard_install() {
   $shortcut->save();
 
   // Enable the admin theme.
-  \Drupal::config('node.settings')->set('use_admin_theme', '1')->save();
+  \Drupal::configFactory()->getEditable('node.settings')->set('use_admin_theme', '1')->save();
 }
diff --git a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
index f7eef52f0a35..4ed1c20b670f 100644
--- a/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
+++ b/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityStorageTest.php
@@ -246,11 +246,16 @@ public function testSaveInsert(EntityInterface $entity) {
         $this->entityTypeId . '_list', // List cache tag.
       ));
 
-    $this->configFactory->expects($this->exactly(2))
+    $this->configFactory->expects($this->exactly(1))
       ->method('get')
       ->with('the_config_prefix.foo')
       ->will($this->returnValue($config_object));
 
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
+
     $this->moduleHandler->expects($this->at(0))
       ->method('invokeAll')
       ->with('test_entity_type_presave');
@@ -311,10 +316,14 @@ public function testSaveUpdate(EntityInterface $entity) {
       ->method('loadMultiple')
       ->with(array('the_config_prefix.foo'))
       ->will($this->returnValue(array()));
-    $this->configFactory->expects($this->exactly(2))
+    $this->configFactory->expects($this->exactly(1))
       ->method('get')
       ->with('the_config_prefix.foo')
       ->will($this->returnValue($config_object));
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.foo')
+      ->will($this->returnValue($config_object));
 
     $this->moduleHandler->expects($this->at(0))
       ->method('invokeAll')
@@ -370,6 +379,10 @@ public function testSaveRename(ConfigEntityInterface $entity) {
 
     $this->configFactory->expects($this->once())
       ->method('rename')
+      ->willReturn($this->configFactory);
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.bar')
       ->will($this->returnValue($config_object));
     $this->configFactory->expects($this->exactly(2))
       ->method('loadMultiple')
@@ -506,8 +519,11 @@ public function testSaveNoMismatch() {
       ->will($this->returnValue($config_object));
     $this->configFactory->expects($this->once())
       ->method('rename')
+      ->willReturn($this->configFactory);
+    $this->configFactory->expects($this->exactly(1))
+      ->method('getEditable')
+      ->with('the_config_prefix.foo')
       ->will($this->returnValue($config_object));
-
     $this->entityQuery->expects($this->once())
       ->method('condition')
       ->will($this->returnSelf());
@@ -736,7 +752,7 @@ public function testDelete() {
       ));
 
     $this->configFactory->expects($this->exactly(2))
-      ->method('get')
+      ->method('getEditable')
       ->will($this->returnValueMap($config_map));
 
     $this->moduleHandler->expects($this->at(0))
diff --git a/core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php b/core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php
new file mode 100644
index 000000000000..8b0bbf8f49cf
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Config/ImmutableConfigTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Config\ImmutableConfigTest.
+ */
+
+namespace Drupal\Tests\Core\Config;
+
+use Drupal\Core\Config\ImmutableConfig;
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Config\ImmutableConfig
+ * @group Config
+ */
+class ImmutableConfigTest extends UnitTestCase {
+
+  /**
+   * The immutable config object under test.
+   *
+   * @var \Drupal\Core\Config\ImmutableConfig
+   */
+  protected $config;
+
+  protected function setUp() {
+    parent::setUp();
+    $storage = $this->getMock('Drupal\Core\Config\StorageInterface');
+    $event_dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
+    $typed_config = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
+    $this->config = new ImmutableConfig('test', $storage, $event_dispatcher, $typed_config);
+  }
+
+  /**
+   * @covers ::set
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not set values on immutable configuration test:name. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testSet() {
+    $this->config->set('name', 'value');
+  }
+
+  /**
+   * @covers ::clear
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not clear name key in immutable configuration test. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testClear() {
+    $this->config->clear('name');
+  }
+
+  /**
+   * @covers ::save
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not save immutable configuration test. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testSave() {
+    $this->config->save();
+  }
+
+  /**
+   * @covers ::delete
+   * @expectedException \Drupal\Core\Config\ImmutableConfigException
+   * @expectedExceptionMessage Can not delete immutable configuration test. Use \Drupal\Core\Config\ConfigFactoryInterface::getEditable() to retrieve a mutable configuration object
+   */
+  public function testDelete() {
+    $this->config->delete();
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php b/core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php
new file mode 100644
index 000000000000..443646bfd220
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/Form/ConfigFormBaseTraitTest.php
@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Tests\Core\Form\ConfigFormBaseTraitTest.
+ */
+
+namespace Drupal\Tests\Core\Form;
+
+use Drupal\Tests\UnitTestCase;
+
+/**
+ * @coversDefaultClass \Drupal\Core\Form\ConfigFormBaseTrait
+ * @group Form
+ */
+class ConfigFormBaseTraitTest extends UnitTestCase {
+
+  /**
+   * @covers ::config
+   */
+  public function testConfig() {
+
+    $trait = $this->getMockForTrait('Drupal\Core\Form\ConfigFormBaseTrait');
+    // Set up some configuration in a mocked config factory.
+    $trait->configFactory = $this->getConfigFactoryStub([
+      'editable.config' => [],
+      'immutable.config' => []
+    ]);
+
+    $trait->expects($this->any())
+      ->method('getEditableConfigNames')
+      ->willReturn(['editable.config']);
+
+    $config_method = new \ReflectionMethod($trait, 'config');
+    $config_method->setAccessible(TRUE);
+
+    // Ensure that configuration that is expected to be mutable is.
+    $result = $config_method->invoke($trait, 'editable.config');
+    $this->assertInstanceOf('\Drupal\Core\Config\Config', $result);
+    $this->assertNotInstanceOf('\Drupal\Core\Config\ImmutableConfig', $result);
+
+    // Ensure that configuration that is expected to be immutable is.
+    $result = $config_method->invoke($trait, 'immutable.config');
+    $this->assertInstanceOf('\Drupal\Core\Config\ImmutableConfig', $result);
+  }
+
+  /**
+   * @covers ::config
+   * @expectedException \LogicException
+   * @expectedExceptionMessage No config factory available for ConfigFormBaseTrait
+   */
+  public function testConfigFactoryException() {
+    $trait = $this->getMockForTrait('Drupal\Core\Form\ConfigFormBaseTrait');
+    $config_method = new \ReflectionMethod($trait, 'config');
+    $config_method->setAccessible(TRUE);
+
+    // There is no config factory available this should result in an exception.
+    $config_method->invoke($trait, 'editable.config');
+  }
+
+  /**
+   * @covers ::config
+   * @expectedException \LogicException
+   * @expectedExceptionMessage No config factory available for ConfigFormBaseTrait
+   */
+  public function testConfigFactoryExceptionInvalidProperty() {
+    $trait = $this->getMockForTrait('Drupal\Core\Form\ConfigFormBaseTrait');
+    $trait->configFactory = TRUE;
+    $config_method = new \ReflectionMethod($trait, 'config');
+    $config_method->setAccessible(TRUE);
+
+    // There is no config factory available this should result in an exception.
+    $config_method->invoke($trait, 'editable.config');
+  }
+
+}
diff --git a/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php b/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
index ea37f39b77c0..3f6093317e8b 100644
--- a/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
@@ -144,7 +144,7 @@ public function testSaveOverride() {
 
     $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->will($this->returnValue($config));
 
     $static_override = new StaticMenuLinkOverrides($config_factory);
@@ -186,7 +186,7 @@ public function testDeleteOverrides($ids, array $old_definitions, array $new_def
 
     $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->once())
-      ->method('get')
+      ->method('getEditable')
       ->will($this->returnValue($config));
 
     $static_override = new StaticMenuLinkOverrides($config_factory);
diff --git a/core/tests/Drupal/Tests/UnitTestCase.php b/core/tests/Drupal/Tests/UnitTestCase.php
index 1a0ac77d0b16..d6deb9eafae2 100644
--- a/core/tests/Drupal/Tests/UnitTestCase.php
+++ b/core/tests/Drupal/Tests/UnitTestCase.php
@@ -100,13 +100,11 @@ protected function assertArrayEquals(array $expected, array $actual, $message =
    *   A MockBuilder object for the ConfigFactory with the desired return values.
    */
   public function getConfigFactoryStub(array $configs = array()) {
-    $config_map = array();
+    $config_get_map = array();
+    $config_editable_map = array();
     // Construct the desired configuration object stubs, each with its own
     // desired return map.
     foreach ($configs as $config_name => $config_values) {
-      $config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
-        ->disableOriginalConstructor()
-        ->getMock();
       $map = array();
       foreach ($config_values as $key => $value) {
         $map[] = array($key, $value);
@@ -114,18 +112,31 @@ public function getConfigFactoryStub(array $configs = array()) {
       // Also allow to pass in no argument.
       $map[] = array('', $config_values);
 
-      $config_object->expects($this->any())
+      $immutable_config_object = $this->getMockBuilder('Drupal\Core\Config\ImmutableConfig')
+        ->disableOriginalConstructor()
+        ->getMock();
+      $immutable_config_object->expects($this->any())
         ->method('get')
         ->will($this->returnValueMap($map));
+      $config_get_map[] = array($config_name, $immutable_config_object);
 
-      $config_map[] = array($config_name, $config_object);
+      $mutable_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
+        ->disableOriginalConstructor()
+        ->getMock();
+      $mutable_config_object->expects($this->any())
+        ->method('get')
+        ->will($this->returnValueMap($map));
+      $config_editable_map[] = array($config_name, $mutable_config_object);
     }
     // Construct a config factory with the array of configuration object stubs
     // as its return map.
     $config_factory = $this->getMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->any())
       ->method('get')
-      ->will($this->returnValueMap($config_map));
+      ->will($this->returnValueMap($config_get_map));
+    $config_factory->expects($this->any())
+      ->method('getEditable')
+      ->will($this->returnValueMap($config_editable_map));
     return $config_factory;
   }
 
diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php
index a43575445adf..76d26fcfdf3c 100644
--- a/sites/default/default.settings.php
+++ b/sites/default/default.settings.php
@@ -551,7 +551,18 @@
  * the default settings.php.
  *
  * Note that any values you provide in these variable overrides will not be
- * modifiable from the Drupal administration interface.
+ * viewable from the Drupal administration interface. The administration
+ * interface displays the values stored in configuration so that you can stage
+ * changes to other environments that don't have the overrides.
+ *
+ * There are particular configuration values that are risky to override. For
+ * example, overriding the list of installed modules in 'core.extension' is not
+ * supported as module install or uninstall has not occurred. Other examples
+ * include field storage configuration, because it has effects on database
+ * structure, and 'core.menu.static_menu_link_overrides' since this is cached in
+ * a way that is not config override aware. Also, note that changing
+ * configuration values in settings.php will not fire any of the configuration
+ * change events.
  */
 # $config['system.site']['name'] = 'My Drupal site';
 # $config['system.theme']['default'] = 'stark';
-- 
GitLab