diff --git a/core/modules/locale/locale.install b/core/modules/locale/locale.install
index 2fe0abd..b439bb6 100644
--- a/core/modules/locale/locale.install
+++ b/core/modules/locale/locale.install
@@ -945,6 +945,29 @@ function locale_update_8015() {
 }
 
 /**
+ * Converts localized date formats.
+ */
+function locale_update_8016() {
+  $configs = array();
+
+  // Fetch all date types from {date_format_type}.
+  $result = db_query('SELECT * FROM {date_format_locale}');
+  foreach ($result as $format) {
+    $language = $format->language;
+    // Create config objects for the language if not yet done.
+    if (!isset($configs[$language])) {
+      $configs[$language] = config('locale.config.' . $language . '.system.date');
+    }
+    $configs[$language]->set('formats.' . $format->type . '.pattern.php', $format->format);
+  }
+
+  // Save all instantiated config objects.
+  foreach ($configs as $config) {
+    $config->save();
+  }
+}
+
+/**
  * @} End of "addtogroup updates-7.x-to-8.x".
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/DateUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/DateUpgradePathTest.php
new file mode 100644
index 0000000..f5d2d9f
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/DateUpgradePathTest.php
@@ -0,0 +1,119 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\system\Tests\Upgrade\DateUpgradePathTest.
+ */
+
+namespace Drupal\system\Tests\Upgrade;
+
+/**
+ * Test upgrade of date formats.
+ */
+class DateUpgradePathTest extends UpgradePathTestBase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Date upgrade test',
+      'description' => 'Upgrade tests for date formats.',
+      'group' => 'Upgrade path',
+    );
+  }
+
+  public function setUp() {
+    $this->databaseDumpFiles = array(
+      drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.bare.standard_all.database.php.gz',
+      drupal_get_path('module', 'system') . '/tests/upgrade/drupal-7.date.database.php',
+    );
+    parent::setUp();
+  }
+
+  /**
+   * Tests that date formats have been upgraded.
+   */
+  public function testDateUpgrade() {
+    $this->assertTrue($this->performUpgrade(), 'The upgrade was completed successfully.');
+
+    // Verify standard date formats.
+    $expected_formats['short'] = array(
+      'name' => 'Short',
+      'pattern' => array(
+        'php' => 'Y/m/d - H:i',
+      ),
+      'locked' => '1',
+    );
+    $expected_formats['medium'] = array(
+      'name' => 'Medium',
+      'pattern' => array(
+        'php' => 'D, d/m/Y - H:i',
+      ),
+      'locked' => '1',
+    );
+    $expected_formats['long'] = array(
+      'name' => 'Long',
+      'pattern' => array(
+        'php' => 'l, Y,  F j - H:i',
+      ),
+      'locked' => '1',
+    );
+
+    // Verify custom date format.
+    $expected_formats['test_custom'] = array(
+      'name' => 'Test Custom',
+      'pattern' => array(
+        'php' => 'd m Y',
+        ),
+      'locked' => '0',
+    );
+
+    foreach ($expected_formats as $type => $format) {
+      $format_info = config('system.date')->get('formats.' . $type);
+
+      $this->assertEqual($format_info['name'], $format['name'], format_string('Config value for @type name is the same', array('@type' => $type)));
+      $this->assertEqual($format_info['locked'], $format['locked'], format_string('Config value for @type locked is the same', array('@type' => $type)));
+      $this->assertEqual($format_info['pattern']['php'], $format['pattern']['php'], format_string('Config value for @type PHP date pattern is the same', array('@type' => $type)));
+
+      // Make sure that the variable was deleted.
+      $this->assertNull(update_variable_get('date_format_' . $type), format_string('Date format variable for @type was deleted.', array('@type' => $type)));
+    }
+
+    $expected_locale_formats = array(
+      array(
+        'langcode' => 'en',
+        'type' => 'long',
+        'format' => 'l, j F, Y - H:i',
+      ),
+      array(
+        'langcode' => 'en',
+        'type' => 'medium',
+        'format' => 'D, m/d/Y - H:i',
+      ),
+      array(
+        'langcode' => 'en',
+        'type' => 'short',
+        'format' => 'm/d/Y - H:i',
+      ),
+      array(
+        'langcode' => 'de',
+        'type' => 'long',
+        'format' => 'l, j. F, Y - H:i',
+      ),
+      array(
+        'langcode' => 'de',
+        'type' => 'medium',
+        'format' => 'D, d/m/Y - H:i',
+      ),
+      array(
+        'langcode' => 'de',
+        'type' => 'short',
+        'format' => 'd/m/Y - H:i',
+      ),
+    );
+
+    $config['en'] = config('locale.config.en.system.date');
+    $config['de'] = config('locale.config.de.system.date');
+    foreach ($expected_locale_formats as $locale_format) {
+      $format = $config[$locale_format['langcode']]->get('formats.' . $locale_format['type'] . '.pattern.php');
+      $this->assertEqual($locale_format['format'], $format);
+    }
+  }
+}
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 33df8c2..267549f 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -678,95 +678,6 @@ function system_schema() {
   $schema['cache_path'] = $schema['cache'];
   $schema['cache_path']['description'] = 'Cache table for path alias lookup.';
 
-  $schema['date_format_type'] = array(
-    'description' => 'Stores configured date format types.',
-    'fields' => array(
-      'type' => array(
-        'description' => 'The date format type, e.g. medium.',
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-      ),
-      'title' => array(
-        'description' => 'The human readable name of the format type.',
-        'type' => 'varchar',
-        'length' => 255,
-        'not null' => TRUE,
-      ),
-      'locked' => array(
-        'description' => 'Whether or not this is a system provided format.',
-        'type' => 'int',
-        'size' => 'tiny',
-        'default' => 0,
-        'not null' => TRUE,
-      ),
-    ),
-    'primary key' => array('type'),
-    'indexes' => array(
-      'title' => array('title'),
-    ),
-  );
-
-  // This table's name is plural as some versions of MySQL can't create a
-  // table named 'date_format'.
-  $schema['date_formats'] = array(
-    'description' => 'Stores configured date formats.',
-    'fields' => array(
-      'dfid' => array(
-        'description' => 'The date format identifier.',
-        'type' => 'serial',
-        'not null' => TRUE,
-        'unsigned' => TRUE,
-      ),
-      'format' => array(
-        'description' => 'The date format string.',
-        'type' => 'varchar',
-        'length' => 100,
-        'not null' => TRUE,
-      ),
-      'type' => array(
-        'description' => 'The date format type, e.g. medium.',
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-      ),
-      'locked' => array(
-        'description' => 'Whether or not this format can be modified.',
-        'type' => 'int',
-        'size' => 'tiny',
-        'default' => 0,
-        'not null' => TRUE,
-      ),
-    ),
-    'primary key' => array('dfid'),
-    'unique keys' => array('formats' => array('format', 'type')),
-  );
-
-  $schema['date_format_locale'] = array(
-    'description' => 'Stores configured date formats for each locale.',
-    'fields' => array(
-      'format' => array(
-        'description' => 'The date format string.',
-        'type' => 'varchar',
-        'length' => 100,
-        'not null' => TRUE,
-      ),
-      'type' => array(
-        'description' => 'The date format type, e.g. medium.',
-        'type' => 'varchar',
-        'length' => 64,
-        'not null' => TRUE,
-      ),
-      'language' => array(
-        'description' => 'A {language}.langcode for this format to be used with.',
-        'type' => 'varchar',
-        'length' => 12,
-        'not null' => TRUE,
-      ),
-    ),
-    'primary key' => array('type', 'language'),
-  );
-
   $schema['flood'] = array(
     'description' => 'Flood controls the threshold of events, such as the number of contact attempts.',
     'fields' => array(
@@ -2381,6 +2292,38 @@ function system_update_8044() {
 }
 
 /**
+ * Converts existing date formats to the new config system.
+ */
+function system_update_8043() {
+  // Get the date config object.
+  $config = config('system.date');
+
+  // Fetch all date types from {date_format_type}.
+  $date_formats = db_query('SELECT * FROM {date_format_type}')->fetchAllAssoc('type', PDO::FETCH_ASSOC);
+  if (!empty($date_formats)) {
+    foreach ($date_formats as $type => $format) {
+      // Set name and locked properties.
+      $config->set("formats.{$type}.name", $format['title']);
+      $config->set("formats.{$type}.locked", $format['locked']);
+
+      // Get the default date format for this type.
+      $variable_name = 'date_format_' . $type;
+      $default_format = update_variable_get($variable_name, NULL);
+      if ($default_format) {
+        // In Drupal 7 we only used PHP date types.
+        $config->set("formats.{$type}.pattern.php", $default_format);
+
+        // Delete the migrated variables.
+        update_variable_del($variable_name);
+      }
+    }
+
+    // Save the date configuration object.
+    $config->save();
+  }
+}
+
+/**
  * @} End of "defgroup updates-7.x-to-8.x".
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/system/tests/upgrade/drupal-7.date.database.php b/core/modules/system/tests/upgrade/drupal-7.date.database.php
new file mode 100644
index 0000000..9f1f601
--- /dev/null
+++ b/core/modules/system/tests/upgrade/drupal-7.date.database.php
@@ -0,0 +1,105 @@
+<?php
+
+/**
+ * @file
+ * Database additions for Drupal\system\Tests\Upgrade\DateUpgradePathTest.
+ *
+ * This dump only contains data and schema components relevant for date
+ * functionality. The bare.standard_all.database.php file is imported before
+ * this dump, so the two form the database structure expected in tests
+ * altogether.
+ */
+
+// Add default format for standard date formats.
+db_insert('variable')
+  ->fields(array(
+    'name',
+    'value',
+  ))
+  ->values(array(
+    'name' => 'date_format_short',
+    'value'=> 's:11:"Y/m/d - H:i";',
+  ))
+  ->values(array(
+    'name' => 'date_format_medium',
+    'value'=> 's:14:"D, d/m/Y - H:i";',
+  ))
+  ->values(array(
+    'name' => 'date_format_long',
+    'value'=> 's:16:"l, Y,  F j - H:i";',
+  ))
+  ->values(array(
+    'name' => 'date_format_test_custom',
+    'value'=> 's:5:"d m Y";',
+  ))
+  ->execute();
+
+// Add custom date types.
+db_insert('date_format_type')
+  ->fields(array(
+    'type',
+    'title',
+    'locked'
+  ))
+  // Custom date format.
+  ->values(array(
+    'type' => 'test_custom',
+    'title' => 'Test Custom',
+    'locked' => '0',
+  ))
+  ->execute();
+
+// Add date formats for custom types.
+db_insert('date_formats')
+  ->fields(array(
+    'dfid',
+    'format',
+    'type',
+    'locked',
+  ))
+  ->values(array(
+    'dfid' => '36',
+    'format' => 'd m Y',
+    'type' => 'test_custom',
+    'locked' => '0',
+  ))
+  ->execute();
+
+// Add localized date formats.
+db_insert('date_format_locale')
+  ->fields(array(
+    'format',
+    'type',
+    'language',
+  ))
+  ->values(array(
+    'format' => 'l, j F, Y - H:i',
+    'type' => 'long',
+    'language' => 'en',
+  ))
+  ->values(array(
+    'format' => 'D, m/d/Y - H:i',
+    'type' => 'medium',
+    'language' => 'en',
+  ))
+  ->values(array(
+    'format' => 'm/d/Y - H:i',
+    'type' => 'short',
+    'language' => 'en',
+  ))
+  ->values(array(
+    'format' => 'l, j. F, Y - H:i',
+    'type' => 'long',
+    'language' => 'de',
+  ))
+  ->values(array(
+    'format' => 'D, d/m/Y - H:i',
+    'type' => 'medium',
+    'language' => 'de',
+  ))
+  ->values(array(
+    'format' => 'd/m/Y - H:i',
+    'type' => 'short',
+    'language' => 'de',
+  ))
+  ->execute();
