diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index a20acd8..d861806 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -516,7 +516,7 @@ function ajax_prepare_response($page_callback_result) {
 
       case MENU_SITE_OFFLINE:
         $commands[] = ajax_command_alert(filter_xss_admin(variable_get('maintenance_mode_message',
-          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal'))))));
+          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => config('system.site')->get('name'))))));
         break;
     }
   }
diff --git a/core/includes/common.inc b/core/includes/common.inc
index a08cafc..a0f4444 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2464,6 +2464,7 @@ function drupal_deliver_html_page($page_callback_result) {
 
   // Menu status constants are integers; page content is a string or array.
   if (is_int($page_callback_result)) {
+    $site_config = config('system.site');
     // @todo: Break these up into separate functions?
     switch ($page_callback_result) {
       case MENU_NOT_FOUND:
@@ -2480,7 +2481,7 @@ function drupal_deliver_html_page($page_callback_result) {
           $_GET['destination'] = current_path();
         }
 
-        $path = drupal_get_normal_path(variable_get('site_404', ''));
+        $path = drupal_get_normal_path($site_config->get('page.404'));
         if ($path && $path != current_path()) {
           // Custom 404 handler. Set the active item in case there are tabs to
           // display, or other dependencies on the path.
@@ -2509,7 +2510,7 @@ function drupal_deliver_html_page($page_callback_result) {
           $_GET['destination'] = current_path();
         }
 
-        $path = drupal_get_normal_path(variable_get('site_403', ''));
+        $path = drupal_get_normal_path($site_config->get('page.403'));
         if ($path && $path != current_path()) {
           // Custom 403 handler. Set the active item in case there are tabs to
           // display or other dependencies on the path.
@@ -2532,7 +2533,7 @@ function drupal_deliver_html_page($page_callback_result) {
         drupal_add_http_header('Status', '503 Service unavailable');
         drupal_set_title(t('Site under maintenance'));
         print theme('maintenance_page', array('content' => filter_xss_admin(variable_get('maintenance_mode_message',
-          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))))));
+          t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => $site_config->get('name')))))));
         break;
     }
   }
diff --git a/core/includes/gettext.inc b/core/includes/gettext.inc
index 4e3b221..ef9d25d 100644
--- a/core/includes/gettext.inc
+++ b/core/includes/gettext.inc
@@ -955,7 +955,7 @@ function _locale_export_po_generate($language = NULL, $strings = array(), $heade
 
   if (!isset($header)) {
     if (isset($language)) {
-      $header = '# ' . $language->name . ' translation of ' . variable_get('site_name', 'Drupal') . "\n";
+      $header = '# ' . $language->name . ' translation of ' . config('system.site')->get('name') . "\n";
       $header .= '# Generated by ' . $user->name . ' <' . $user->mail . ">\n";
       $header .= "#\n";
       $header .= "msgid \"\"\n";
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index e62a7b5..36a35c0 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1896,8 +1896,11 @@ function install_configure_form_validate($form, &$form_state) {
 function install_configure_form_submit($form, &$form_state) {
   global $user;
 
-  variable_set('site_name', $form_state['values']['site_name']);
-  variable_set('site_mail', $form_state['values']['site_mail']);
+  config('system.site')
+    ->set('name', $form_state['values']['site_name'])
+    ->set('mail', $form_state['values']['site_mail'])
+    ->save();
+
   variable_set('date_default_timezone', $form_state['values']['date_default_timezone']);
   variable_set('site_default_country', $form_state['values']['site_default_country']);
 
diff --git a/core/includes/mail.inc b/core/includes/mail.inc
index f58a76e..c03fb0e 100644
--- a/core/includes/mail.inc
+++ b/core/includes/mail.inc
@@ -118,7 +118,8 @@ define('MAIL_LINE_ENDINGS', isset($_SERVER['WINDIR']) || strpos($_SERVER['SERVER
  *   accepted at php-level, which still doesn't guarantee it to be delivered.)
  */
 function drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE) {
-  $default_from = variable_get('site_mail', ini_get('sendmail_from'));
+  $site_mail = config('system.site')->get('mail');
+  $default_from = (!empty($site_mail) ? $site_mail : ini_get('sendmail_from'));
 
   // Bundle up the variables into a structured array for altering.
   $message = array(
diff --git a/core/includes/path.inc b/core/includes/path.inc
index 0c7e4d4..62a58a6 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -22,7 +22,7 @@ function drupal_path_initialize() {
   // If on the front page, resolve to the front page path, including for calls
   // to current_path() while drupal_get_normal_path() is in progress.
   if (empty($path)) {
-    $path = variable_get('site_frontpage', 'user');
+    $path = config('system.site')->get('page.front');
     _current_path($path);
   }
 
@@ -298,7 +298,7 @@ function drupal_is_front_page() {
   $is_front_page = &$drupal_static_fast['is_front_page'];
 
   if (!isset($is_front_page)) {
-    $is_front_page = (current_path() == variable_get('site_frontpage', 'user'));
+    $is_front_page = (current_path() == config('system.site')->get('page.front'));
   }
 
   return $is_front_page;
@@ -329,7 +329,7 @@ function drupal_match_path($path, $patterns) {
     $replacements = array(
       '|',
       '.*',
-      '\1' . preg_quote(variable_get('site_frontpage', 'user'), '/') . '\2'
+      '\1' . preg_quote(config('system.site')->get('page.front'), '/') . '\2'
     );
     $patterns_quoted = preg_quote($patterns, '/');
     $regexps[$patterns] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 7d638f6..2466670 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2530,17 +2530,18 @@ function template_preprocess_html(&$variables) {
     drupal_add_html_head_link(array('rel' => 'shortcut icon', 'href' => drupal_strip_dangerous_protocols($favicon), 'type' => $type));
   }
 
+  $site_config = config('system.site');
   // Construct page title.
   if (drupal_get_title()) {
     $head_title = array(
       'title' => strip_tags(drupal_get_title()),
-      'name' => check_plain(variable_get('site_name', 'Drupal')),
+      'name' => check_plain($site_config->get('name')),
     );
   }
   else {
-    $head_title = array('name' => check_plain(variable_get('site_name', 'Drupal')));
-    if (variable_get('site_slogan', '')) {
-      $head_title['slogan'] = filter_xss_admin(variable_get('site_slogan', ''));
+    $head_title = array('name' => check_plain($site_config->get('name')));
+    if ($site_config->get('slogan')) {
+      $head_title['slogan'] = filter_xss_admin($site_config->get('slogan'));
     }
   }
   $variables['head_title_array'] = $head_title;
@@ -2574,6 +2575,7 @@ function template_preprocess_html(&$variables) {
  */
 function template_preprocess_page(&$variables) {
   $language_interface = drupal_container()->get(LANGUAGE_TYPE_INTERFACE);
+  $site_config = config('system.site');
 
   // Move some variables to the top level for themer convenience and template cleanliness.
   $variables['show_messages'] = $variables['page']['#show_messages'];
@@ -2602,8 +2604,8 @@ function template_preprocess_page(&$variables) {
   $variables['main_menu']         = theme_get_setting('toggle_main_menu') ? menu_main_menu() : array();
   $variables['secondary_menu']    = theme_get_setting('toggle_secondary_menu') ? menu_secondary_menu() : array();
   $variables['action_links']      = menu_local_actions();
-  $variables['site_name']         = (theme_get_setting('toggle_name') ? filter_xss_admin(variable_get('site_name', 'Drupal')) : '');
-  $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ? filter_xss_admin(variable_get('site_slogan', '')) : '');
+  $variables['site_name']         = (theme_get_setting('toggle_name') ? filter_xss_admin($site_config->get('name')) : '');
+  $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ? filter_xss_admin($site_config->get('slogan')) : '');
   $variables['tabs']              = menu_local_tabs();
 
   if ($node = menu_get_object()) {
@@ -2784,17 +2786,18 @@ function template_preprocess_maintenance_page(&$variables) {
     $variables['layout'] = ($variables['layout'] == 'first') ? 'both' : 'second';
   }
 
+  $site_config = config('system.site');
   // Construct page title
   if (drupal_get_title()) {
     $head_title = array(
       'title' => strip_tags(drupal_get_title()),
-      'name' => variable_get('site_name', 'Drupal'),
+      'name' => $site_config->get('name'),
     );
   }
   else {
-    $head_title = array('name' => variable_get('site_name', 'Drupal'));
-    if (variable_get('site_slogan', '')) {
-      $head_title['slogan'] = variable_get('site_slogan', '');
+    $head_title = array('name' => $site_config->get('name'));
+    if ($site_config->get('slogan')) {
+      $head_title['slogan'] = $site_config->get('slogan');
     }
   }
 
@@ -2813,8 +2816,8 @@ function template_preprocess_maintenance_page(&$variables) {
   $variables['messages']          = $variables['show_messages'] ? theme('status_messages') : '';
   $variables['main_menu']         = array();
   $variables['secondary_menu']    = array();
-  $variables['site_name']         = (theme_get_setting('toggle_name') ? variable_get('site_name', 'Drupal') : '');
-  $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ? variable_get('site_slogan', '') : '');
+  $variables['site_name']         = (theme_get_setting('toggle_name') ? $site_config->get('name') : '');
+  $variables['site_slogan']       = (theme_get_setting('toggle_slogan') ? $site_config->get('slogan') : '');
   $variables['tabs']              = '';
   $variables['title']             = drupal_get_title();
 
diff --git a/core/includes/update.inc b/core/includes/update.inc
index b0d09a7..41667b3 100644
--- a/core/includes/update.inc
+++ b/core/includes/update.inc
@@ -9,6 +9,7 @@
  */
 
 use Drupal\Component\Graph\Graph;
+use Drupal\Core\Config\FileStorage;
 
 /**
  * Minimum schema version of Drupal 7 required for upgrade to Drupal 8.
@@ -877,64 +878,56 @@ function update_retrieve_dependencies() {
  * Provide a generalised method to migrate variables from Drupal 7 to Drupal 8's
  * configuration management system.
  *
- * @param $config_name
- *   The name of the configuration object to retrieve. The name corresponds to
- *   an XML configuration file. For example, passing "book.admin" will return
- *   the config object containing the contents of book.admin.xml.
- * @param $variable_map
- *   An array to map new to old configuration naming conventions. Example:
+ * @param string $config_name
+ *   The configuration object name to retrieve.
+ * @param array $variable_map
+ *   An associative array that maps old variables names to new configuration
+ *   object keys; e.g.:
  *   @code
- *     array('new_config' => 'old_config')
+ *     array('old_variable' => 'new_config.sub_key')
  *   @endcode
- *   This would update the value for new_config to the value old_config has in
- *   the variable table.
+ *   This would migrate the value contained in variable name 'old_variable' into
+ *   the data key 'new_config.sub_key' of the configuration object $config_name.
  */
-function update_variables_to_config($config_name, array $variable_map = array()) {
+function update_variables_to_config($config_name, array $variable_map) {
+  // Build the new configuration object.
+  // This potentially loads an existing configuration object, in case another
+  // update function migrated configuration values into $config_name already.
   $config = config($config_name);
-  $config_data = array_keys($config->get());
-
-  if (!empty($config_data)) {
-    // Build a list of variables to select from the database and build a mapping
-    // of variable names to config keys.
-    foreach ($config_data as $config_key) {
-      if (isset($variable_map[$config_key])) {
-        $variables[] = $variable_map[$config_key];
-        $config_keys[$variable_map[$config_key]] = $config_key;
-      }
-      else {
-        $variables[] = $config_key;
-        $config_keys[$config_key] = $config_key;
-      }
-    }
 
-    // Get any variables currently defined that match the new setting names in
-    // the config file.
-    $query = db_select('variable', 'v')
-      ->fields('v')
-      ->condition('name', $variables, 'IN');
-
-    $var_values = $query->execute()->fetchAllKeyed(0);
-    if (!empty($var_values)) {
-      // Update the config system settings to use the values previously stored in
-      // the variable table.
-      try {
-        foreach($var_values as $name => $val) {
-          $config->set($config_keys[$name], unserialize($val));
-        }
-        $config->save();
-        // Delete the old variables. The config system will throw an exception if a
-        // value cannot be saved, so this code will not run if there is a problem
-        // running the update.
-        $del = db_delete('variable')->condition('name', $variables, 'IN');
-        $del->execute();
-      }
-      // @TODO We may want to do different error handling for different
-      // exception types, but for now we'll just log the exception.
-      catch (Exception $e) {
-        watchdog_exception('update', $e);
-      }
+  // Extract the module namespace/owner from the configuration object name.
+  $module = strtok($config_name, '.');
+
+  // Load and set default configuration values.
+  // Throws a FileStorageReadException if there is no default configuration
+  // file, which is required to exist.
+  $file = new FileStorage($config_name);
+  $file->setPath(drupal_get_path('module', $module) . '/config');
+  $data = $file->read();
+
+  // Apply the default values.
+  $config->setData($data);
+
+  // Fetch existing variables.
+  $variables = db_query('SELECT name, value FROM {variable} WHERE name IN (:variables)', array(':variables' => array_keys($variable_map)))->fetchAllKeyed();
+
+  // Set configuration values according to the provided variable mapping.
+  foreach ($variable_map as $variable_name => $config_key) {
+    // This function migrates variables regardless of their value, including
+    // NULL values. Any possibly required customizations need to be performed
+    // manually, either via variable_set() before calling this function or via
+    // config() after calling this function.
+    if (isset($variables[$variable_name])) {
+      $value = unserialize($variables[$variable_name]);
+      $config->set($config_key, $value);
     }
   }
+
+  // Save the configuration object.
+  $config->save();
+
+  // Delete the migrated variables.
+  db_delete('variable')->condition('name', array_keys($variable_map), 'IN')->execute();
 }
 
 /**
diff --git a/core/lib/Drupal/Core/Config/FileStorage.php b/core/lib/Drupal/Core/Config/FileStorage.php
index 5e2ac1e..ed53f4b 100644
--- a/core/lib/Drupal/Core/Config/FileStorage.php
+++ b/core/lib/Drupal/Core/Config/FileStorage.php
@@ -105,13 +105,14 @@ class FileStorage {
    */
   public function read() {
     if (!$this->exists()) {
-      throw new FileStorageReadException('Configuration file does not exist.');
+      // Use var_export to quote $this->name to separate from text.
+      throw new FileStorageReadException('Configuration file ' . var_export($this->name, TRUE) . ' does not exist.');
     }
 
     $data = file_get_contents($this->getFilePath());
     $data = $this->decode($data);
     if ($data === FALSE) {
-      throw new FileStorageReadException('Unable to decode configuration file.');
+      throw new FileStorageReadException('Failed to decode configuration file ' . var_export($this->name, TRUE) . '.');
     }
     return $data;
   }
diff --git a/core/modules/aggregator/aggregator.pages.inc b/core/modules/aggregator/aggregator.pages.inc
index 7f82077..0c82b05 100644
--- a/core/modules/aggregator/aggregator.pages.inc
+++ b/core/modules/aggregator/aggregator.pages.inc
@@ -11,7 +11,7 @@
  * @see aggregator_menu()
  */
 function aggregator_page_last() {
-  drupal_add_feed('aggregator/rss', variable_get('site_name', 'Drupal') . ' ' . t('aggregator'));
+  drupal_add_feed('aggregator/rss', config('system.site')->get('name') . ' ' . t('aggregator'));
 
   $items = aggregator_load_feed_items('sum');
 
@@ -61,7 +61,7 @@ function aggregator_page_source_form($form, $form_state, $feed) {
  * @ingroup forms
  */
 function aggregator_page_category($category) {
-  drupal_add_feed('aggregator/rss/' . $category['cid'], variable_get('site_name', 'Drupal') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
+  drupal_add_feed('aggregator/rss/' . $category['cid'], config('system.site')->get('name') . ' ' . t('aggregator - @title', array('@title' => $category['title'])));
 
   // It is safe to include the cid in the query because it's loaded from the
   // database by aggregator_category_load().
@@ -452,7 +452,7 @@ function theme_aggregator_page_rss($variables) {
     $items .= format_rss_item($feed->ftitle . ': ' . $feed->title, $feed->link, $feed->description, array('pubDate' => date('r', $feed->timestamp)));
   }
 
-  $site_name = variable_get('site_name', 'Drupal');
+  $site_name = config('system.site')->get('name');
   $url = url((isset($category) ? 'aggregator/categories/' . $category->cid : 'aggregator'), array('absolute' => TRUE));
   $description = isset($category) ? t('@site_name - aggregated feeds in category @title', array('@site_name' => $site_name, '@title' => $category->title)) : t('@site_name - aggregated feeds', array('@site_name' => $site_name));
 
@@ -504,7 +504,7 @@ function theme_aggregator_page_opml($variables) {
   $output  = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
   $output .= "<opml version=\"1.1\">\n";
   $output .= "<head>\n";
-  $output .= '<title>' . check_plain(variable_get('site_name', 'Drupal')) . "</title>\n";
+  $output .= '<title>' . check_plain(config('system.site')->get('name')) . "</title>\n";
   $output .= '<dateModified>' . gmdate(DATE_RFC2822, REQUEST_TIME) . "</dateModified>\n";
   $output .= "</head>\n";
   $output .= "<body>\n";
diff --git a/core/modules/block/block.install b/core/modules/block/block.install
index 632e106..7544c33 100644
--- a/core/modules/block/block.install
+++ b/core/modules/block/block.install
@@ -224,6 +224,8 @@ function block_install() {
 
 /**
  * Block cache is always enabled in 8.x.
+ *
+ * @ingroup config_upgrade
  */
 function block_update_8000() {
   variable_del('block_cache');
diff --git a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
index 38e65c4..696a281 100644
--- a/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
+++ b/core/modules/block/lib/Drupal/block/Tests/BlockTest.php
@@ -167,7 +167,7 @@ class BlockTest extends WebTestBase {
   function testBlockVisibility() {
     // Enable Node module and change the front page path to 'node'.
     module_enable(array('node'));
-    variable_set('site_frontpage', 'node');
+    config('system.site')->set('page.front', 'node')->save();
 
     $block = array();
 
diff --git a/core/modules/config/config.test b/core/modules/config/config.test
index 257ab0f..26092d1 100644
--- a/core/modules/config/config.test
+++ b/core/modules/config/config.test
@@ -315,16 +315,15 @@ class ConfOverrideTestCase extends WebTestBase {
 }
 
 /**
- * Tests function providing configuration upgrade from Drupal 7 to 8.
+ * Tests migration of variables into configuration objects.
  */
-class ConfUpdate7to8TestCase extends WebTestBase {
+class ConfigUpgradeTestCase extends WebTestBase {
   protected $testContent = 'Olá, Sao Paulo!';
 
   public static function getInfo() {
     return array(
-      'name' => 'Configuration update from Drupal 7 to 8',
-      'description' => 'Tests the ability to update Drupal 7 variables to the
-        configuration management system.',
+      'name' => 'Variable migration',
+      'description' => 'Tests migration of variables into configuration objects.',
       'group' => 'Configuration',
     );
   }
@@ -335,18 +334,32 @@ class ConfUpdate7to8TestCase extends WebTestBase {
   }
 
   /**
-   * Test configuration update function.
+   * Tests update_variables_to_config().
    */
   function testConfigurationUpdate() {
     // Ensure that the variable table has the object. The variable table will
     // remain in place for Drupal 8 to provide an upgrade path for overridden
     // variables.
-    db_merge('variable')->key(array('name' => 'config_test_foo'))->fields(array('value' => serialize($this->testContent)))->execute();
-    db_merge('variable')->key(array('name' => 'config_bar'))->fields(array('value' => serialize($this->testContent)))->execute();
-
-    update_variables_to_config('config.test', array('config_test_bar' => 'config_bar'));
-    $config = config('config.test');
-    $this->assertEqual($config->get('config_test_foo'), $this->testContent);
-    $this->assertEqual($config->get('config_test_bar'), $this->testContent);
+    db_insert('variable')
+      ->fields(array('name', 'value'))
+      ->values(array('config_upgrade_foo', serialize($this->testContent)))
+      ->values(array('config_upgrade_bar', serialize($this->testContent)))
+      ->execute();
+
+    update_variables_to_config('config_upgrade.test', array(
+      'config_upgrade_bar' => 'parent.bar',
+      'config_upgrade_foo' => 'foo',
+      // Non-existing variable.
+      'config_upgrade_baz' => 'parent.baz',
+    ));
+
+    $config = config('config_upgrade.test');
+    $this->assertIdentical($config->get('foo'), $this->testContent);
+    $this->assertIdentical($config->get('parent.bar'), $this->testContent);
+    $this->assertIdentical($config->get('parent.baz'), 'Baz');
+
+    // Verify that variables have been deleted.
+    $variables = db_query('SELECT name FROM {variable} WHERE name IN (:names)', array(':names' => array('config_upgrade_bar', 'config_upgrade_foo')))->fetchCol();
+    $this->assertFalse($variables);
   }
 }
diff --git a/core/modules/contact/contact.install b/core/modules/contact/contact.install
index 7ddea45..5956740 100644
--- a/core/modules/contact/contact.install
+++ b/core/modules/contact/contact.install
@@ -68,11 +68,15 @@ function contact_schema() {
  * Implements hook_install().
  */
 function contact_install() {
+  $site_mail = config('system.site')->get('mail');
+  if (empty($site_mail)) {
+    $site_mail = ini_get('sendmail_from');
+  }
   // Insert a default contact category.
   db_insert('contact')
     ->fields(array(
       'category' => 'Website feedback',
-      'recipients' => variable_get('site_mail', ini_get('sendmail_from')),
+      'recipients' => $site_mail,
       'selected' => 1,
       'reply' => '',
     ))
diff --git a/core/modules/contact/contact.module b/core/modules/contact/contact.module
index 48c12d9..dc43fc9 100644
--- a/core/modules/contact/contact.module
+++ b/core/modules/contact/contact.module
@@ -170,7 +170,7 @@ function contact_load($cid) {
 function contact_mail($key, &$message, $params) {
   $language = $message['language'];
   $variables = array(
-    '!site-name' => variable_get('site_name', 'Drupal'),
+    '!site-name' => config('system.site')->get('name'),
     '!subject' => $params['subject'],
     '!category' => isset($params['category']['category']) ? $params['category']['category'] : '',
     '!form-url' => url(current_path(), array('absolute' => TRUE, 'language' => $language)),
diff --git a/core/modules/filter/filter.module b/core/modules/filter/filter.module
index 94d8a03..23fad42 100644
--- a/core/modules/filter/filter.module
+++ b/core/modules/filter/filter.module
@@ -1277,7 +1277,7 @@ function _filter_html_tips($filter, $format, $long = FALSE) {
   $output .= '<p>' . t('This site allows HTML content. While learning all of HTML may feel intimidating, learning how to use a very small number of the most basic HTML "tags" is very easy. This table provides examples for each tag that is enabled on this site.') . '</p>';
   $output .= '<p>' . t('For more information see W3C\'s <a href="@html-specifications">HTML Specifications</a> or use your favorite search engine to find other sites that explain HTML.', array('@html-specifications' => 'http://www.w3.org/TR/html/')) . '</p>';
   $tips = array(
-    'a' => array(t('Anchors are used to make links to other pages.'), '<a href="' . $base_url . '">' . check_plain(variable_get('site_name', 'Drupal')) . '</a>'),
+    'a' => array(t('Anchors are used to make links to other pages.'), '<a href="' . $base_url . '">' . check_plain(config('system.site')->get('name')) . '</a>'),
     'br' => array(t('By default line break tags are automatically added, so use this tag to add additional ones. Use of this tag is different because it is not used with an open/close pair like all the others. Use the extra " /" inside the tag to maintain XHTML 1.0 compatibility'), t('Text with <br />line break')),
     'p' => array(t('By default paragraph tags are automatically added, so use this tag to add additional ones.'), '<p>' . t('Paragraph one.') . '</p> <p>' . t('Paragraph two.') . '</p>'),
     'strong' => array(t('Strong', array(), array('context' => 'Font weight')), '<strong>' . t('Strong', array(), array('context' => 'Font weight')) . '</strong>'),
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
index 61fd67f..5476a7a 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocalePathTest.php
@@ -25,7 +25,7 @@ class LocalePathTest extends WebTestBase {
     parent::setUp(array('node', 'locale', 'path'));
 
     $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page'));
-    variable_set('site_frontpage', 'node');
+    config('system.site')->set('page.front', 'node')->save();
   }
 
   /**
diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index b29bdee..ac03baa 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -157,6 +157,8 @@ function locale_update_8000() {
 
 /**
  * Language type 'language' renamed to 'language_interface'.
+ *
+ * @ingroup config_upgrade
  */
 function locale_update_8001() {
   // Only change language_types if we had this setting saved. Keep order
@@ -242,6 +244,8 @@ function locale_update_8002() {
 
 /**
  * Converts language domains to new format.
+ *
+ * @ingroup config_upgrade
  */
 function locale_update_8003() {
   $message = '';
@@ -274,6 +278,8 @@ function locale_update_8003() {
 
 /**
  * Rename language providers to language negotiation methods.
+ *
+ * @ingroup config_upgrade
  */
 function locale_update_8004() {
   $types = variable_get('language_types', NULL);
@@ -437,6 +443,8 @@ function locale_update_8006() {
 
 /**
  * Convert language_negotiation_* variables to use the new callbacks.
+ *
+ * @ingroup config_upgrade
  */
 function locale_update_8007() {
   $variable_names = array(
@@ -510,6 +518,8 @@ function locale_update_8007() {
 
 /**
  * Rename the option variables of the locale language negotiation.
+ *
+ * @ingroup config_upgrade
  */
 function locale_update_8008() {
   $variable_name_map = array(
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index ee89059..981fdba 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -475,7 +475,6 @@ function node_uninstall() {
   variable_del('node_admin_theme');
   variable_del('node_cron_last');
   variable_del('node_recent_block_count');
-  variable_del('default_nodes_main');
 }
 
 /**
@@ -511,26 +510,11 @@ function _update_7000_node_get_types() {
  */
 
 /**
- * Set 'node' as front page path if it implicitly was before.
- *
- * Node module became optional. The default front page path was changed to
- * 'user'. Since 'node' was the implicit default front page path previously and
- * may not have been explicitly configured as such, this update ensures that the
- * old implicit default is still the default.
- *
- * @see http://drupal.org/node/375397
- */
-function node_update_8000() {
-  $front_page = variable_get('site_frontpage');
-  if (!isset($front_page)) {
-    variable_set('site_frontpage', 'node');
-  }
-}
-
-/**
  * Rename node type language variable names.
  *
  * @see http://drupal.org/node/540294
+ *
+ * @ingroup config_upgrade
  */
 function node_update_8001() {
   $types = db_query('SELECT type FROM {node_type}')->fetchCol();
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 3c3881d..05e2335 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -2429,7 +2429,7 @@ function node_feed($nids = FALSE, $channel = array()) {
 
   $channel_defaults = array(
     'version'     => '2.0',
-    'title'       => variable_get('site_name', 'Drupal'),
+    'title'       => config('system.site')->get('name'),
     'link'        => $base_url,
     'description' => config('system.rss-publishing')->get('feed_description'),
     'language'    => $language_content->langcode
@@ -2481,6 +2481,7 @@ function node_view_multiple($nodes, $view_mode = 'teaser', $weight = 0, $langcod
  * @see node_menu()
  */
 function node_page_default() {
+  $site_config = config('system.site');
   $select = db_select('node', 'n')
     ->fields('n', array('nid', 'sticky', 'created'))
     ->condition('promote', 1)
@@ -2488,7 +2489,7 @@ function node_page_default() {
     ->orderBy('sticky', 'DESC')
     ->orderBy('created', 'DESC')
     ->extend('PagerDefault')
-    ->limit(variable_get('default_nodes_main', 10))
+    ->limit($site_config->get('default_nodes_main'))
     ->addTag('node_access');
 
   $nids = $select->execute()->fetchCol();
@@ -2498,7 +2499,7 @@ function node_page_default() {
     $build = node_view_multiple($nodes);
 
     // 'rss.xml' is a path, not a file, registered in node_menu().
-    drupal_add_feed('rss.xml', variable_get('site_name', 'Drupal') . ' ' . t('RSS'));
+    drupal_add_feed('rss.xml', $site_config->get('name') . ' ' . t('RSS'));
     $build['pager'] = array(
       '#theme' => 'pager',
       '#weight' => 5,
@@ -2506,7 +2507,7 @@ function node_page_default() {
     drupal_set_title('');
   }
   else {
-    drupal_set_title(t('Welcome to @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), PASS_THROUGH);
+    drupal_set_title(t('Welcome to @site-name', array('@site-name' => $site_config->get('name'))), PASS_THROUGH);
 
     $default_message = '<p>' . t('No front page content has been created yet.') . '</p>';
 
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 02c0883..2be68e6 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -635,7 +635,7 @@ function overlay_overlay_parent_initialize() {
   // Let the client side know which paths are administrative.
   $paths = path_get_admin_paths();
   foreach ($paths as &$type) {
-    $type = str_replace('<front>', variable_get('site_frontpage', 'user'), $type);
+    $type = str_replace('<front>', config('system.site')->get('page.front'), $type);
   }
   drupal_add_js(array('overlay' => array('paths' => $paths)), 'setting');
   $path_prefixes = array();
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 33b26e3..c5f1001 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -752,7 +752,7 @@ abstract class WebTestBase extends TestBase {
 
     // Restore necessary variables.
     variable_set('install_task', 'done');
-    variable_set('site_mail', 'simpletest@example.com');
+    config('system.site')->set('mail', 'simpletest@example.com')->save();
     variable_set('date_default_timezone', date_default_timezone_get());
 
     // Set up English language.
diff --git a/core/modules/simpletest/simpletest.test b/core/modules/simpletest/simpletest.test
index cc4e026..19fb031 100644
--- a/core/modules/simpletest/simpletest.test
+++ b/core/modules/simpletest/simpletest.test
@@ -49,7 +49,7 @@ class SimpleTestFunctionalTest extends WebTestBase {
     if (!$this->inCURL()) {
       $this->drupalGet('node');
       $this->assertTrue($this->drupalGetHeader('Date'), t('An HTTP header was received.'));
-      $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), t('Site title matches.'));
+      $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => config('system.site')->get('name'))), t('Site title matches.'));
       $this->assertNoTitle('Foo', t('Site title does not match.'));
       // Make sure that we are locked out of the installer when prefixing
       // using the user-agent header. This is an important security check.
diff --git a/core/modules/system/config/system.site.yml b/core/modules/system/config/system.site.yml
new file mode 100644
index 0000000..886ef5f
--- /dev/null
+++ b/core/modules/system/config/system.site.yml
@@ -0,0 +1,8 @@
+name: Drupal
+mail: ''
+slogan: ''
+default_nodes_main: '10'
+page:
+    front: user
+    403: ''
+    404: ''
diff --git a/core/modules/system/language.api.php b/core/modules/system/language.api.php
index 9f28619..e6dbd3d 100644
--- a/core/modules/system/language.api.php
+++ b/core/modules/system/language.api.php
@@ -28,11 +28,11 @@ function hook_language_init() {
 
   switch (drupal_container()->get(LANGUAGE_TYPE_INTERFACE)->langcode) {
     case 'it':
-      $conf['site_name'] = 'Il mio sito Drupal';
+      $conf['system.site']['name'] = 'Il mio sito Drupal';
       break;
 
     case 'fr':
-      $conf['site_name'] = 'Mon site Drupal';
+      $conf['system.site']['name'] = 'Mon site Drupal';
       break;
   }
 }
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index fc0e8bb..5a54481 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -1462,6 +1462,12 @@ function system_ip_blocking_delete_submit($form, &$form_state) {
  * @see system_settings_form()
  */
 function system_site_information_settings() {
+  $site_config = config('system.site');
+  $site_mail = $site_config->get('mail');
+  if (empty($site_mail)) {
+    $site_mail = ini_get('sendmail_from');
+  }
+
   $form['site_information'] = array(
     '#type' => 'fieldset',
     '#title' => t('Site details'),
@@ -1469,19 +1475,19 @@ function system_site_information_settings() {
   $form['site_information']['site_name'] = array(
     '#type' => 'textfield',
     '#title' => t('Site name'),
-    '#default_value' => variable_get('site_name', 'Drupal'),
+    '#default_value' => $site_config->get('name'),
     '#required' => TRUE
   );
   $form['site_information']['site_slogan'] = array(
     '#type' => 'textfield',
     '#title' => t('Slogan'),
-    '#default_value' => variable_get('site_slogan', ''),
+    '#default_value' => $site_config->get('slogan'),
     '#description' => t("How this is used depends on your site's theme."),
   );
   $form['site_information']['site_mail'] = array(
     '#type' => 'email',
     '#title' => t('E-mail address'),
-    '#default_value' => variable_get('site_mail', ini_get('sendmail_from')),
+    '#default_value' => $site_mail,
     '#description' => t("The <em>From</em> address in automated e-mails sent during registration and new password requests, and other notifications. (Use an address ending in your site's domain to help prevent this e-mail being flagged as spam.)"),
     '#required' => TRUE,
   );
@@ -1492,17 +1498,17 @@ function system_site_information_settings() {
   $form['front_page']['site_frontpage'] = array(
     '#type' => 'textfield',
     '#title' => t('Default front page'),
-    '#default_value' => (variable_get('site_frontpage') != 'user' ? drupal_get_path_alias(variable_get('site_frontpage', 'user')) : ''),
+    '#default_value' => ($site_config->get('page.front') != 'user' ? drupal_get_path_alias($site_config->get('page.front')) : ''),
     '#size' => 40,
     '#description' => t('Optionally, specify a relative URL to display as the front page.  Leave blank to display the default content feed.'),
     '#field_prefix' => url(NULL, array('absolute' => TRUE)),
   );
   $form['front_page']['default_nodes_main'] = array(
     '#type' => 'select', '#title' => t('Number of posts on front page'),
-    '#default_value' => variable_get('default_nodes_main', 10),
+    '#default_value' => $site_config->get('default_nodes_main'),
     '#options' => drupal_map_assoc(array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 25, 30)),
     '#description' => t('The maximum number of posts displayed on overview pages such as the front page.'),
-    '#access' => (variable_get('site_frontpage') == 'node'),
+    '#access' => ($site_config->get('page.front') == 'node'),
   );
   $form['error_page'] = array(
     '#type' => 'fieldset',
@@ -1511,7 +1517,7 @@ function system_site_information_settings() {
   $form['error_page']['site_403'] = array(
     '#type' => 'textfield',
     '#title' => t('Default 403 (access denied) page'),
-    '#default_value' => variable_get('site_403', ''),
+    '#default_value' => $site_config->get('page.403'),
     '#size' => 40,
     '#description' => t('This page is displayed when the requested document is denied to the current user. Leave blank to display a generic "access denied" page.'),
     '#field_prefix' => url(NULL, array('absolute' => TRUE)),
@@ -1519,7 +1525,7 @@ function system_site_information_settings() {
   $form['error_page']['site_404'] = array(
     '#type' => 'textfield',
     '#title' => t('Default 404 (not found) page'),
-    '#default_value' => variable_get('site_404', ''),
+    '#default_value' => $site_config->get('page.404'),
     '#size' => 40,
     '#description' => t('This page is displayed when no other content matches the requested document. Leave blank to display a generic "page not found" page.'),
     '#field_prefix' => url(NULL, array('absolute' => TRUE)),
@@ -1527,6 +1533,8 @@ function system_site_information_settings() {
 
   $form['#validate'][] = 'system_site_information_settings_validate';
 
+  // @todo Replace with configuration system settings form.
+  $form['#submit'][] = 'system_site_information_settings_submit';
   return system_settings_form($form);
 }
 
@@ -1565,6 +1573,21 @@ function system_site_information_settings_validate($form, &$form_state) {
 }
 
 /**
+ * Form submission handler for system_site_information_settings().
+ */
+function system_site_information_settings_submit($form, &$form_state) {
+  config('system.site')
+    ->set('name', $form_state['values']['site_name'])
+    ->set('mail', $form_state['values']['site_mail'])
+    ->set('slogan', $form_state['values']['site_slogan'])
+    ->set('default_nodes_main', $form_state['values']['default_nodes_main'])
+    ->set('page.front', $form_state['values']['site_frontpage'])
+    ->set('page.403', $form_state['values']['site_403'])
+    ->set('page.404', $form_state['values']['site_404'])
+    ->save();
+}
+
+/**
  * Form builder; Cron form.
  *
  * @see system_settings_form()
@@ -2235,7 +2258,7 @@ function system_site_maintenance_mode() {
   $form['maintenance_mode_message'] = array(
     '#type' => 'textarea',
     '#title' => t('Message to display when in maintenance mode'),
-    '#default_value' => variable_get('maintenance_mode_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')))),
+    '#default_value' => variable_get('maintenance_mode_message', t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => config('system.site')->get('name')))),
   );
 
   return system_settings_form($form);
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 2fb21c7..3a01bba 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -1525,7 +1525,7 @@ function hook_mail_alter(&$message) {
       $message['send'] = FALSE;
       return;
     }
-    $message['body'][] = "--\nMail sent out from " . variable_get('site_name', t('Drupal'));
+    $message['body'][] = "--\nMail sent out from " . config('system.site')->get('name');
   }
 }
 
@@ -1990,7 +1990,7 @@ function hook_watchdog(array $log_entry) {
   $to = 'someone@example.com';
   $params = array();
   $params['subject'] = t('[@site_name] @severity_desc: Alert from your web site', array(
-    '@site_name' => variable_get('site_name', 'Drupal'),
+    '@site_name' => config('system.site')->get('name'),
     '@severity_desc' => $severity_list[$log_entry['severity']],
   ));
 
@@ -2056,7 +2056,7 @@ function hook_mail($key, &$message, $params) {
   $account = $params['account'];
   $context = $params['context'];
   $variables = array(
-    '%site_name' => variable_get('site_name', 'Drupal'),
+    '%site_name' => config('system.site')->get('name'),
     '%username' => user_format_name($account),
   );
   if ($context['hook'] == 'taxonomy') {
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 5581d01..9bb71da 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -1688,6 +1688,17 @@ function system_update_last_removed() {
 }
 
 /**
+ * @defgroup config_upgrade Configuration system upgrade functions
+ * @{
+ * Module update functions that
+ * - update variables prior to configuration system conversions
+ * - convert variables to the new configuration system
+ * - update configuration system values after conversion
+ *
+ * @} End of "defgroup config_upgrade".
+ */
+
+/**
  * @defgroup updates-7.x-to-8.x Updates from 7.x to 8.x
  * @{
  * Update functions from 7.x to 8.x.
@@ -1713,7 +1724,14 @@ function system_update_8001() {
 }
 
 /**
- * Set Bartik as default theme if it implicitly was the default before.
+ * Set 'node' as front page path and Bartik as default theme if it implicitly was before.
+ *
+ * Node module became optional. The default front page path was changed to
+ * 'user'. Since 'node' was the implicit default front page path previously and
+ * may not have been explicitly configured as such, this update ensures that the
+ * old implicit default is still the default.
+ *
+ * @see http://drupal.org/node/375397
  *
  * The default theme for Drupal core was changed from Bartik to Stark.
  * Installation profiles (including Standard and Minimal) were changed to
@@ -1723,8 +1741,14 @@ function system_update_8001() {
  * default.
  *
  * @see http://drupal.org/node/1181776
+ *
+ * @ingroup config_upgrade
  */
 function system_update_8002() {
+  $front_page = variable_get('site_frontpage');
+  if (!isset($front_page)) {
+    variable_set('site_frontpage', 'node');
+  }
   $theme = variable_get('theme_default');
   if (!isset($theme)) {
     variable_set('theme_default', 'bartik');
@@ -1864,16 +1888,47 @@ function system_update_8008() {
 
 /**
  * Moves cron system settings from variable to config.
+ *
+ * @ingroup config_upgrade
  */
 function system_update_8009() {
-  update_variables_to_config('system.cron');
+  update_variables_to_config('system.cron', array(
+    'cron_max_threshold' => 'cron_max_threshold',
+    'cron_safe_threshold' => 'cron_safe_threshold',
+    'cron_threshold_warning' => 'cron_threshold_warning',
+    'cron_threshold_error' => 'cron_threshold_error',
+    'cron_key' => 'cron_key',
+  ));
 }
 
 /**
- * Moves system settings from variable to config.
+ * Moves RSS system settings from variable to config.
+ *
+ * @ingroup config_upgrade
  */
 function system_update_8010() {
-  update_variables_to_config('system.rss-publishing');
+  update_variables_to_config('system.rss-publishing', array(
+    'feed_description' => 'feed_description',
+    'feed_default_items' => 'feed_default_items',
+    'feed_item_length' => 'feed_item_length',
+  ));
+}
+
+/**
+ * Moves site system settings from variable to config.
+ *
+ * @ingroup config_upgrade
+ */
+function system_update_8011() {
+  update_variables_to_config('system.site', array(
+    'site_name' => 'name',
+    'site_mail' => 'mail',
+    'site_slogan' => 'slogan',
+    'default_nodes_main' => 'default_nodes_main',
+    'site_frontpage' => 'page.front',
+    'site_403' => 'page.403',
+    'site_404' => 'page.404',
+  ));
 }
 
 /**
diff --git a/core/modules/system/system.test b/core/modules/system/system.test
index ec1a9a6..f01fa38 100644
--- a/core/modules/system/system.test
+++ b/core/modules/system/system.test
@@ -1055,7 +1055,7 @@ class AccessDeniedTestCase extends WebTestBase {
 
     // Log back in, set the custom 403 page to /user and remove the block
     $this->drupalLogin($this->admin_user);
-    variable_set('site_403', 'user');
+    config('system.site')->set('page.403', 'user')->save();
     $this->drupalPost('admin/structure/block', array('blocks[user_login][region]' => '-1'), t('Save blocks'));
 
     // Check that we can log in from the 403 page.
@@ -1126,7 +1126,7 @@ class SiteMaintenanceTestCase extends WebTestBase {
     parent::setUp(array('node'));
 
     // Configure 'node' as front page.
-    variable_set('site_frontpage', 'node');
+    config('system.site')->set('page.front', 'node')->save();
 
     // Create a user allowed to access site in maintenance mode.
     $this->user = $this->drupalCreateUser(array('access site in maintenance mode'));
@@ -1147,7 +1147,7 @@ class SiteMaintenanceTestCase extends WebTestBase {
 
     $admin_message = t('Operating in maintenance mode. <a href="@url">Go online.</a>', array('@url' => url('admin/config/development/maintenance')));
     $user_message = t('Operating in maintenance mode.');
-    $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')));
+    $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => config('system.site')->get('name')));
 
     $this->drupalGet('');
     $this->assertRaw($admin_message, t('Found the site maintenance mode message.'));
@@ -1536,7 +1536,7 @@ class FrontPageTestCase extends WebTestBase {
     $this->node_path = "node/" . $this->drupalCreateNode(array('promote' => 1))->nid;
 
     // Configure 'node' as front page.
-    variable_set('site_frontpage', 'node');
+    config('system.site')->set('page.front', 'node')->save();
     // Enable front page logging in system_test.module.
     variable_set('front_page_output', 1);
   }
@@ -2038,13 +2038,15 @@ class TokenReplaceTestCase extends WebTestBase {
     );
 
     // Set a few site variables.
-    variable_set('site_name', '<strong>Drupal<strong>');
-    variable_set('site_slogan', '<blink>Slogan</blink>');
+    config('system.site')
+      ->set('name', '<strong>Drupal<strong>')
+      ->set('slogan', '<blink>Slogan</blink>')
+      ->save();
 
     // Generate and test sanitized tokens.
     $tests = array();
-    $tests['[site:name]'] = check_plain(variable_get('site_name', 'Drupal'));
-    $tests['[site:slogan]'] = check_plain(variable_get('site_slogan', ''));
+    $tests['[site:name]'] = check_plain(config('system.site')->get('name'));
+    $tests['[site:slogan]'] = check_plain(config('system.site')->get('slogan'));
     $tests['[site:mail]'] = 'simpletest@example.com';
     $tests['[site:url]'] = url('<front>', $url_options);
     $tests['[site:url-brief]'] = preg_replace(array('!^https?://!', '!/$!'), '', url('<front>', $url_options));
@@ -2059,8 +2061,8 @@ class TokenReplaceTestCase extends WebTestBase {
     }
 
     // Generate and test unsanitized tokens.
-    $tests['[site:name]'] = variable_get('site_name', 'Drupal');
-    $tests['[site:slogan]'] = variable_get('site_slogan', '');
+    $tests['[site:name]'] = config('system.site')->get('name');
+    $tests['[site:slogan]'] = config('system.site')->get('slogan');
 
     foreach ($tests as $input => $expected) {
       $output = token_replace($input, array(), array('language' => $language_interface, 'sanitize' => FALSE));
diff --git a/core/modules/system/system.tokens.inc b/core/modules/system/system.tokens.inc
index 2492890..d3df60e 100644
--- a/core/modules/system/system.tokens.inc
+++ b/core/modules/system/system.tokens.inc
@@ -145,17 +145,17 @@ function system_tokens($type, $tokens, array $data = array(), array $options = a
     foreach ($tokens as $name => $original) {
       switch ($name) {
         case 'name':
-          $site_name = variable_get('site_name', 'Drupal');
+          $site_name = config('system.site')->get('name');
           $replacements[$original] = $sanitize ? check_plain($site_name) : $site_name;
           break;
 
         case 'slogan':
-          $slogan = variable_get('site_slogan', '');
+          $slogan = config('system.site')->get('slogan');
           $replacements[$original] = $sanitize ? check_plain($slogan) : $slogan;
           break;
 
         case 'mail':
-          $replacements[$original] = variable_get('site_mail', '');
+          $replacements[$original] = config('system.site')->get('mail');
           break;
 
         case 'url':
diff --git a/core/modules/system/tests/bootstrap.test b/core/modules/system/tests/bootstrap.test
index 098e12e..f219209 100644
--- a/core/modules/system/tests/bootstrap.test
+++ b/core/modules/system/tests/bootstrap.test
@@ -114,8 +114,10 @@ class BootstrapPageCacheTestCase extends WebTestBase {
   function setUp() {
     parent::setUp(array('node', 'system_test'));
 
-    variable_set('site_name', 'Drupal');
-    variable_set('site_frontpage', 'node');
+    config('system.site')
+      ->set('name', 'Drupal')
+      ->set('page.front', 'node')
+      ->save();
   }
 
   /**
@@ -229,7 +231,7 @@ class BootstrapPageCacheTestCase extends WebTestBase {
     $this->drupalGet('');
     $this->assertEqual($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Page was cached.'));
     $this->assertFalse($this->drupalGetHeader('Content-Encoding'), t('A Content-Encoding header was not sent.'));
-    $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), t('Site title matches.'));
+    $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => config('system.site')->get('name'))), t('Site title matches.'));
     $this->assertRaw('</html>', t('Page was not compressed.'));
   }
 }
diff --git a/core/modules/system/tests/common.test b/core/modules/system/tests/common.test
index b50daad..c61e033 100644
--- a/core/modules/system/tests/common.test
+++ b/core/modules/system/tests/common.test
@@ -887,7 +887,7 @@ class CommonDrupalHTTPRequestTestCase extends WebTestBase {
     $result = drupal_http_request(url('node', array('absolute' => TRUE)));
     $this->assertEqual($result->code, 200, t('Fetched page successfully.'));
     $this->drupalSetContent($result->data);
-    $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => variable_get('site_name', 'Drupal'))), t('Site title matches.'));
+    $this->assertTitle(t('Welcome to @site-name | @site-name', array('@site-name' => config('system.site')->get('name'))), t('Site title matches.'));
 
     // Test that code and status message is returned.
     $result = drupal_http_request(url('pagedoesnotexist', array('absolute' => TRUE)));
diff --git a/core/modules/system/tests/menu.test b/core/modules/system/tests/menu.test
index dbd94a1..c006ef1 100644
--- a/core/modules/system/tests/menu.test
+++ b/core/modules/system/tests/menu.test
@@ -248,7 +248,7 @@ class MenuRouterTestCase extends WebTestBase {
   function testMaintenanceModeLoginPaths() {
     variable_set('maintenance_mode', TRUE);
 
-    $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => variable_get('site_name', 'Drupal')));
+    $offline_message = t('@site is currently under maintenance. We should be back shortly. Thank you for your patience.', array('@site' => config('system.site')->get('name')));
     $this->drupalGet('node');
     $this->assertText($offline_message);
     $this->drupalGet('menu_login_callback');
@@ -1636,8 +1636,10 @@ class MenuTrailTestCase extends MenuWebTestCase {
    */
   function testCustom403And404Pages() {
     // Set the custom 403 and 404 pages we will use.
-    variable_set('site_403', 'menu-test/custom-403-page');
-    variable_set('site_404', 'menu-test/custom-404-page');
+    config('system.site')
+      ->set('page.403', 'menu-test/custom-403-page')
+      ->set('page.404', 'menu-test/custom-404-page')
+      ->save();
 
     // Define the paths we'll visit to trigger 403 and 404 responses during
     // this test, and the expected active trail for each case.
diff --git a/core/modules/system/tests/modules/config_upgrade/config/config.test.yml b/core/modules/system/tests/modules/config_upgrade/config/config.test.yml
deleted file mode 100644
index 4e5eb16..0000000
--- a/core/modules/system/tests/modules/config_upgrade/config/config.test.yml
+++ /dev/null
@@ -1,2 +0,0 @@
-config_test_foo: bar
-config_test_bar: foo
diff --git a/core/modules/system/tests/modules/config_upgrade/config/config_upgrade.test.yml b/core/modules/system/tests/modules/config_upgrade/config/config_upgrade.test.yml
new file mode 100644
index 0000000..3957538
--- /dev/null
+++ b/core/modules/system/tests/modules/config_upgrade/config/config_upgrade.test.yml
@@ -0,0 +1,4 @@
+parent:
+    bar: Bar
+    baz: Baz
+foo: Foo
diff --git a/core/modules/system/tests/path.test b/core/modules/system/tests/path.test
index 271cd91..982550b 100644
--- a/core/modules/system/tests/path.test
+++ b/core/modules/system/tests/path.test
@@ -29,7 +29,7 @@ class DrupalMatchPathTestCase extends WebTestBase {
 
     // Set up a random site front page to test the '<front>' placeholder.
     $this->front = $this->randomName();
-    variable_set('site_frontpage', $this->front);
+    config('system.site')->set('page.front', $this->front)->save();
     // Refresh our static variables from the database.
     $this->refreshVariables();
   }
diff --git a/core/modules/system/tests/theme.test b/core/modules/system/tests/theme.test
index d7c6fb2..c2e3009 100644
--- a/core/modules/system/tests/theme.test
+++ b/core/modules/system/tests/theme.test
@@ -31,7 +31,7 @@ class ThemeUnitTest extends WebTestBase {
   function testThemeSuggestions() {
     // Set the front page as something random otherwise the CLI
     // test runner fails.
-    variable_set('site_frontpage', 'nobody-home');
+    config('system.site')->set('page.front', 'nobody-home')->save();
     $args = array('node', '1', 'edit');
     $suggestions = theme_get_suggestions($args, 'page');
     $this->assertEqual($suggestions, array('page__node', 'page__node__%', 'page__node__1', 'page__node__edit'), t('Found expected node edit page suggestions'));
@@ -75,7 +75,7 @@ class ThemeUnitTest extends WebTestBase {
     $original_path = _current_path();
     // Set the current path to node because theme_get_suggestions() will query
     // it to see if we are on the front page.
-    variable_set('site_frontpage', 'node');
+    config('system.site')->set('page.front', 'node')->save();
     _current_path('node');
     $suggestions = theme_get_suggestions(array('node'), 'page');
     // Set it back to not annoy the batch runner.
@@ -320,7 +320,7 @@ class ThemeFunctionsTestCase extends WebTestBase {
     // Required to verify the "active" class in expected links below, and
     // because the current path is different when running tests manually via
     // simpletest.module ('batch') and via the testing framework ('').
-    _current_path(variable_get('site_frontpage', 'user'));
+    _current_path(config('system.site')->get('page.front'));
 
     // Verify that a list of links is properly rendered.
     $variables = array();
diff --git a/core/modules/system/tests/upgrade/upgrade.test b/core/modules/system/tests/upgrade/upgrade.test
index 2f942fa..429bddb 100644
--- a/core/modules/system/tests/upgrade/upgrade.test
+++ b/core/modules/system/tests/upgrade/upgrade.test
@@ -128,6 +128,7 @@ abstract class UpgradePathTestCase extends WebTestBase {
     $this->prepareD8Session();
 
     // Restore necessary variables.
+    // @todo Convert into config('system.site')->set('mail')?
     $this->variable_set('site_mail', 'simpletest@example.com');
 
     drupal_set_time_limit($this->timeLimit);
@@ -142,6 +143,8 @@ abstract class UpgradePathTestCase extends WebTestBase {
    * @param $value
    *   The value to set. This can be any PHP data type; these functions take care
    *   of serialization as necessary.
+   *
+   * @todo Update for D8 configuration system.
    */
   protected function variable_set($name, $value) {
     db_delete('variable')
diff --git a/core/modules/taxonomy/taxonomy.pages.inc b/core/modules/taxonomy/taxonomy.pages.inc
index c84a6bd..33c06fe 100644
--- a/core/modules/taxonomy/taxonomy.pages.inc
+++ b/core/modules/taxonomy/taxonomy.pages.inc
@@ -42,7 +42,7 @@ function taxonomy_term_page(Term $term) {
     'term' => taxonomy_term_view($term, 'full'),
   );
 
-  if ($nids = taxonomy_select_nodes($term->tid, TRUE, variable_get('default_nodes_main', 10))) {
+  if ($nids = taxonomy_select_nodes($term->tid, TRUE, config('system.site')->get('default_nodes_main'))) {
     $nodes = node_load_multiple($nids);
     $build += node_view_multiple($nodes);
     $build['pager'] = array(
@@ -68,7 +68,7 @@ function taxonomy_term_page(Term $term) {
  */
 function taxonomy_term_feed(Term $term) {
   $channel['link'] = url('taxonomy/term/' . $term->tid, array('absolute' => TRUE));
-  $channel['title'] = variable_get('site_name', 'Drupal') . ' - ' . $term->name;
+  $channel['title'] = config('system.site')->get('name') . ' - ' . $term->name;
   // Only display the description if we have a single term, to avoid clutter and confusion.
   // HTML will be removed from feed description.
   $channel['description'] = check_markup($term->description, $term->format, '', TRUE);
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index 4b3eab2..c3a95f9 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -500,7 +500,7 @@ function _update_get_cached_available_releases() {
 function update_mail($key, &$message, $params) {
   $language = $message['language'];
   $langcode = $language->langcode;
-  $message['subject'] .= t('New release(s) available for !site_name', array('!site_name' => variable_get('site_name', 'Drupal')), array('langcode' => $langcode));
+  $message['subject'] .= t('New release(s) available for !site_name', array('!site_name' => config('system.site')->get('name')), array('langcode' => $langcode));
   foreach ($params as $msg_type => $msg_reason) {
     $message['body'][] = _update_message_text($msg_type, $msg_reason, FALSE, $language);
   }
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index cfde270..5e9f4cc 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1876,7 +1876,7 @@ function user_login($form, &$form_state) {
     ),
   );
 
-  $form['name']['#description'] = t('Enter your @s username.', array('@s' => variable_get('site_name', 'Drupal')));
+  $form['name']['#description'] = t('Enter your @s username.', array('@s' => config('system.site')->get('name')));
   $form['pass'] = array('#type' => 'password',
     '#title' => t('Password'),
     '#description' => t('Enter the password that accompanies your username.'),
@@ -3337,7 +3337,11 @@ function _user_mail_notify($op, $account, $language = NULL) {
     if ($op == 'register_pending_approval') {
       // If a user registered requiring admin approval, notify the admin, too.
       // We use the site default language for this.
-      drupal_mail('user', 'register_pending_approval_admin', variable_get('site_mail', ini_get('sendmail_from')), language_default(), $params);
+      $site_mail = config('system.site')->get('mail');
+      if (empty($site_mail)) {
+        $site_mail = ini_get('sendmail_from');
+      }
+      drupal_mail('user', 'register_pending_approval_admin', $site_mail, language_default(), $params);
     }
   }
   return empty($mail) ? NULL : $mail['result'];
diff --git a/core/themes/bartik/template.php b/core/themes/bartik/template.php
index 7db1a31..eaeb38d 100644
--- a/core/themes/bartik/template.php
+++ b/core/themes/bartik/template.php
@@ -43,6 +43,7 @@ function bartik_process_html(&$variables) {
  * Implements hook_process_HOOK() for page.tpl.php.
  */
 function bartik_process_page(&$variables) {
+  $site_config = config('system.site');
   // Hook into color.module.
   if (module_exists('color')) {
     _color_page_alter($variables);
@@ -53,11 +54,11 @@ function bartik_process_page(&$variables) {
   $variables['hide_site_slogan'] = theme_get_setting('toggle_slogan') ? FALSE : TRUE;
   if ($variables['hide_site_name']) {
     // If toggle_name is FALSE, the site_name will be empty, so we rebuild it.
-    $variables['site_name'] = filter_xss_admin(variable_get('site_name', 'Drupal'));
+    $variables['site_name'] = filter_xss_admin($site_config->get('name'));
   }
   if ($variables['hide_site_slogan']) {
     // If toggle_site_slogan is FALSE, the site_slogan will be empty, so we rebuild it.
-    $variables['site_slogan'] = filter_xss_admin(variable_get('site_slogan', ''));
+    $variables['site_slogan'] = filter_xss_admin($site_config->get('slogan'));
   }
   // Since the title and the shortcut link are both block level elements,
   // positioning them next to each other is much simpler with a wrapper div.
@@ -94,17 +95,18 @@ function bartik_preprocess_maintenance_page(&$variables) {
  * Implements hook_process_HOOK() for maintenance-page.tpl.php.
  */
 function bartik_process_maintenance_page(&$variables) {
+  $site_config = config('system.site');
   // Always print the site name and slogan, but if they are toggled off, we'll
   // just hide them visually.
   $variables['hide_site_name']   = theme_get_setting('toggle_name') ? FALSE : TRUE;
   $variables['hide_site_slogan'] = theme_get_setting('toggle_slogan') ? FALSE : TRUE;
   if ($variables['hide_site_name']) {
     // If toggle_name is FALSE, the site_name will be empty, so we rebuild it.
-    $variables['site_name'] = filter_xss_admin(variable_get('site_name', 'Drupal'));
+    $variables['site_name'] = filter_xss_admin($site_config->get('name'));
   }
   if ($variables['hide_site_slogan']) {
     // If toggle_site_slogan is FALSE, the site_slogan will be empty, so we rebuild it.
-    $variables['site_slogan'] = filter_xss_admin(variable_get('site_slogan', ''));
+    $variables['site_slogan'] = filter_xss_admin($site_config->get('slogan'));
   }
 }
 
diff --git a/profiles/minimal/minimal.install b/profiles/minimal/minimal.install
index e02ffcc..2f9c9b8 100644
--- a/profiles/minimal/minimal.install
+++ b/profiles/minimal/minimal.install
@@ -79,7 +79,7 @@ function minimal_install() {
   $query->execute();
 
   // Set front page to "node".
-  variable_set('site_frontpage', 'node');
+  config('system.site')->set('page.front', 'node')->save();
 
   // Allow visitor account creation, but with administrative approval.
   variable_set('user_register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL);
diff --git a/profiles/standard/standard.install b/profiles/standard/standard.install
index eef8d0c..e70052e 100644
--- a/profiles/standard/standard.install
+++ b/profiles/standard/standard.install
@@ -206,7 +206,7 @@ function standard_install() {
   $query->execute();
 
   // Set front page to "node".
-  variable_set('site_frontpage', 'node');
+  config('system.site')->set('page.front', 'node')->save();
 
   // Insert default pre-defined node types into the database. For a complete
   // list of available node type attributes, refer to the node type API
