diff --git a/core/includes/common.inc b/core/includes/common.inc
index 4f72021..9fe3742 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -1575,12 +1575,14 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL
 
   // If we have a non-custom date format use the provided date format pattern.
   if ($type != 'custom') {
-    $format = config('system.date')->get('formats.' . $type . '.pattern.' . $key);
+    if ($date_format = entity_load('date_format', $type)) {
+      $format = $date_format->getPattern($key);
+    }
   }
 
   // Fall back to medium if a format was not found.
   if (empty($format)) {
-    $format = config('system.date')->get('formats.medium.pattern.' . $key);
+    $format = entity_load('date_format', 'medium')->getPattern($key);
   }
 
   // Call $date->format().
diff --git a/core/lib/Drupal/Core/Entity/EntityManager.php b/core/lib/Drupal/Core/Entity/EntityManager.php
index 24e7890..2d5786d 100644
--- a/core/lib/Drupal/Core/Entity/EntityManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityManager.php
@@ -185,6 +185,7 @@ public function getFormController($entity_type, $operation) {
       $class = $this->getControllerClass($entity_type, 'form', $operation);
       if (in_array('Drupal\Core\Entity\EntityControllerInterface', class_implements($class))) {
         $this->controllers['form'][$operation][$entity_type] = $class::createInstance($this->container, $entity_type, $this->getDefinition($entity_type));
+        $this->controllers['form'][$operation][$entity_type]->setOperation($operation);
       }
       else {
         $this->controllers['form'][$operation][$entity_type] = new $class($operation);
diff --git a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/formatter/DatetimeDefaultFormatter.php b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/formatter/DatetimeDefaultFormatter.php
index d5610f3..87e4dab 100644
--- a/core/modules/datetime/lib/Drupal/datetime/Plugin/field/formatter/DatetimeDefaultFormatter.php
+++ b/core/modules/datetime/lib/Drupal/datetime/Plugin/field/formatter/DatetimeDefaultFormatter.php
@@ -100,10 +100,10 @@ public function settingsForm(array $form, array &$form_state) {
     $element = array();
 
     $time = new DrupalDateTime();
-    $format_types = system_get_date_formats();
+    $format_types = entity_load_multiple('date_format');
     if (!empty($format_types)) {
       foreach ($format_types as $type => $type_info) {
-        $options[$type] = $type_info['name'] . ' (' . format_date($time->format('U'), $type) . ')';
+        $options[$type] = $type_info->label() . ' (' . format_date($time->format('U'), $type) . ')';
       }
     }
 
diff --git a/core/modules/system/config/system.date.yml b/core/modules/system/config/system.date.yml
index 55c6e75..55a35c1 100644
--- a/core/modules/system/config/system.date.yml
+++ b/core/modules/system/config/system.date.yml
@@ -1,64 +1,3 @@
 first_day: '0'
 country:
   default: ''
-formats:
-  long:
-    name: 'Default Long Date'
-    pattern:
-      php: 'l, F j, Y - H:i'
-      intl: 'EEEE, LLLL d, yyyy - kk:mm'
-    locked: 0
-  medium:
-    name: 'Default Medium Date'
-    pattern:
-      php: 'D, m/d/Y - H:i'
-      intl: 'ccc, MM/dd/yyyy - kk:mm'
-    locked: 0
-  short:
-    name: 'Default Short Date'
-    pattern:
-      php: 'm/d/Y - H:i'
-      intl: 'MM/dd/yyyy - kk:mm'
-    locked: 0
-  html_datetime:
-    name: 'HTML Datetime'
-    pattern:
-      php: 'Y-m-d\TH:i:sO'
-      intl: 'yyyy-MM-dd''T''kk:mm:ssZZ'
-    locked: 1
-  html_date:
-    name: 'HTML Date'
-    pattern:
-      php: 'Y-m-d'
-      intl: 'yyyy-MM-dd'
-    locked: 1
-  html_time:
-    name: 'HTML Time'
-    pattern:
-      php: 'H:i:s'
-      intl: 'H:mm:ss'
-    locked: 1
-  html_yearless_date:
-    name: 'HTML Yearless date'
-    pattern:
-      php: 'm-d'
-      intl: 'MM-d'
-    locked: 1
-  html_week:
-    name: 'HTML Week'
-    pattern:
-      php: 'Y-\WW'
-      intl: 'Y-''W''WW'
-    locked: 1
-  html_month:
-    name: 'HTML Month'
-    pattern:
-      php: 'Y-m'
-      intl: 'Y-MM'
-    locked: 1
-  html_year:
-    name: 'HTML Year'
-    pattern:
-      php: 'Y'
-      intl: 'Y'
-    locked: 1
diff --git a/core/modules/system/config/system.date_format.html_date.yml b/core/modules/system/config/system.date_format.html_date.yml
new file mode 100644
index 0000000..72ec3b2
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_date.yml
@@ -0,0 +1,7 @@
+id: html_date
+label: 'HTML Date'
+pattern:
+  php: 'Y-m-d'
+  intl: 'yyyy-MM-dd'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.html_datetime.yml b/core/modules/system/config/system.date_format.html_datetime.yml
new file mode 100644
index 0000000..8f2c382
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_datetime.yml
@@ -0,0 +1,7 @@
+id: html_datetime
+label: 'Default Short Date'
+pattern:
+  php: 'Y-m-d\TH:i:sO'
+  intl: 'yyyy-MM-dd''T''kk:mm:ssZZ'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.html_month.yml b/core/modules/system/config/system.date_format.html_month.yml
new file mode 100644
index 0000000..a82eb59
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_month.yml
@@ -0,0 +1,7 @@
+id: html_month
+label: 'Default Short Date'
+pattern:
+  php: 'Y-m'
+  intl: 'Y-MM'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.html_time.yml b/core/modules/system/config/system.date_format.html_time.yml
new file mode 100644
index 0000000..a890cd3
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_time.yml
@@ -0,0 +1,7 @@
+id: html_time
+label: 'Default Short Date'
+pattern:
+  php: 'H:i:s'
+  intl: 'H:mm:ss'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.html_week.yml b/core/modules/system/config/system.date_format.html_week.yml
new file mode 100644
index 0000000..e820bff
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_week.yml
@@ -0,0 +1,7 @@
+id: html_week
+label: 'Default Short Date'
+pattern:
+  php: 'Y-\WW'
+  intl: 'Y-''W''WW'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.html_year.yml b/core/modules/system/config/system.date_format.html_year.yml
new file mode 100644
index 0000000..9bf4a5e
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_year.yml
@@ -0,0 +1,7 @@
+id: html_year
+label: 'Default Short Date'
+pattern:
+  php: 'Y'
+  intl: 'Y'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.html_yearless_date.yml b/core/modules/system/config/system.date_format.html_yearless_date.yml
new file mode 100644
index 0000000..f2a6bde
--- /dev/null
+++ b/core/modules/system/config/system.date_format.html_yearless_date.yml
@@ -0,0 +1,7 @@
+id: html_yearless_date
+label: 'Default Short Date'
+pattern:
+  php: 'm-d'
+  intl: 'MM-d'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.long.yml b/core/modules/system/config/system.date_format.long.yml
new file mode 100644
index 0000000..93217e8
--- /dev/null
+++ b/core/modules/system/config/system.date_format.long.yml
@@ -0,0 +1,7 @@
+id: long
+label: 'Default Long Date'
+pattern:
+  php: 'l, F j, Y - H:i'
+  intl: 'EEEE, LLLL d, yyyy - kk:mm'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.medium.yml b/core/modules/system/config/system.date_format.medium.yml
new file mode 100644
index 0000000..527eda8
--- /dev/null
+++ b/core/modules/system/config/system.date_format.medium.yml
@@ -0,0 +1,7 @@
+id: medium
+label: 'Default Medium Date'
+pattern:
+  php: 'D, m/d/Y - H:i'
+  intl: 'ccc, MM/dd/yyyy - kk:mm'
+status: '1'
+langcode: en
diff --git a/core/modules/system/config/system.date_format.short.yml b/core/modules/system/config/system.date_format.short.yml
new file mode 100644
index 0000000..b0855dd
--- /dev/null
+++ b/core/modules/system/config/system.date_format.short.yml
@@ -0,0 +1,7 @@
+id: short
+label: 'Default Short Date'
+pattern:
+  php: 'm/d/Y - H:i'
+  intl: 'MM/dd/yyyy - kk:mm'
+status: '1'
+langcode: en
diff --git a/core/modules/system/lib/Drupal/system/DateFormatAddFormController.php b/core/modules/system/lib/Drupal/system/DateFormatAddFormController.php
new file mode 100644
index 0000000..ad077f9
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/DateFormatAddFormController.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\DateFormatAddFormController.
+ */
+
+namespace Drupal\system;
+
+/**
+ * @todo.
+ */
+class DateFormatAddFormController extends DateFormatFormControllerBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, array &$form_state) {
+    $actions = parent::actions($form, $form_state);
+    $actions['submit']['#value'] = t('Add format');
+    return $actions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submit(array $form, array &$form_state) {
+    parent::submit($form, $form_state);
+    drupal_set_message(t('Custom date format added.'));
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/DateFormatEditFormController.php b/core/modules/system/lib/Drupal/system/DateFormatEditFormController.php
new file mode 100644
index 0000000..a584b30
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/DateFormatEditFormController.php
@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\DateFormatEditFormController.
+ */
+
+namespace Drupal\system;
+
+/**
+ * @todo.
+ */
+class DateFormatEditFormController extends DateFormatFormControllerBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, array &$form_state) {
+    $form = parent::form($form, $form_state);
+
+    $now = t('Displayed as %date', array('%date' => format_date(REQUEST_TIME, $this->entity->id())));
+    $form['date_format_pattern']['#field_suffix'] = ' <small id="edit-date-format-suffix">' . $now . '</small>';
+    $form['date_format_pattern']['#default_value'] = $this->entity->pattern[$this->patternType];
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function actions(array $form, array &$form_state) {
+    $actions = parent::actions($form, $form_state);
+    $actions['submit']['#value'] = t('Save format');
+    unset($actions['delete']);
+    return $actions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submit(array $form, array &$form_state) {
+    parent::submit($form, $form_state);
+    drupal_set_message(t('Custom date format updated.'));
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/DateFormatFormControllerBase.php b/core/modules/system/lib/Drupal/system/DateFormatFormControllerBase.php
new file mode 100644
index 0000000..7024bf6
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/DateFormatFormControllerBase.php
@@ -0,0 +1,194 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\DateFormatFormControllerBase.
+ */
+
+namespace Drupal\system;
+
+use Drupal\Core\Ajax\AjaxResponse;
+use Drupal\Core\Ajax\ReplaceCommand;
+use Drupal\Core\Entity\EntityControllerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * @todo.
+ */
+abstract class DateFormatFormControllerBase extends EntityFormController implements EntityControllerInterface {
+
+  /**
+   * The date pattern type.
+   *
+   * @var string
+   */
+  protected $patternType;
+
+  /**
+   * The entity query.
+   *
+   * @var \Drupal\Core\Entity\Query\QueryInterface
+   */
+  protected $entityQuery;
+
+  /**
+   * Constructs a new date format form.
+   *
+   * @param \Drupal\Core\Entity\Query\QueryFactory $factory
+   *   The entity query factory.
+   */
+  function __construct(QueryFactory $factory) {
+    $date = new DrupalDateTime();
+    $this->patternType = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
+
+    $this->entityQuery = $factory->get('date_format');
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $container->get('entity.query')
+    );
+  }
+
+  /**
+   * Checks for an existing date format.
+   *
+   * @param string|int $entity_id
+   *   The entity ID.
+   * @param array $element
+   *   The form element.
+   * @param array $form_state
+   *   The form state.
+   *
+   * @return bool
+   *   TRUE if this format already exists, FALSE otherwise.
+   */
+  public static function exists($entity_id, array $element,  array $form_state) {
+    return (bool) entity_load('date_format', $entity_id);
+  }
+
+  /**
+   * @param array $form
+   * @param array $form_state
+   *
+   * @return \Drupal\Core\Ajax\AjaxResponse
+   */
+  public static function dateTimeLookup(array $form, array $form_state) {
+    $format = '';
+    if (!empty($form_state['values']['date_format_pattern'])) {
+      $format = t('Displayed as %date_format', array('%date_format' => format_date(REQUEST_TIME, 'custom', $form_state['values']['date_format_pattern'])));
+    }
+    // Return a command instead of a string, since the Ajax framework
+    // automatically prepends an additional empty DIV element for a string, which
+    // breaks the layout.
+    $response = new AjaxResponse();
+    $response->addCommand(new ReplaceCommand('#edit-date-format-suffix', '<small id="edit-date-format-suffix">' . $format . '</small>'));
+    return $response;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function form(array $form, array &$form_state) {
+    $form = parent::form($form, $form_state);
+    form_load_include($form_state, 'admin.inc', 'system');
+
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#title' => 'Name',
+      '#maxlength' => 100,
+      '#description' => t('Name of the date format'),
+      '#default_value' => $this->entity->label(),
+    );
+
+    $form['id'] = array(
+      '#type' => 'machine_name',
+      '#title' => t('Machine-readable name'),
+      '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
+      '#disabled' => !$this->entity->isNew(),
+      '#default_value' => $this->entity->id(),
+      '#machine_name' => array(
+        'exists' => array($this, 'exists'),
+      ),
+    );
+
+    if (class_exists('intlDateFormatter')) {
+      $description = t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://userguide.icu-project.org/formatparse/datetime'));
+    }
+    else {
+      $description = t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://php.net/manual/function.date.php'));
+    }
+    $form['date_format_pattern'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Format string'),
+      '#maxlength' => 100,
+      '#description' => $description,
+      '#default_value' => '',
+      '#field_suffix' => ' <small id="edit-date-format-suffix"></small>',
+      '#ajax' => array(
+        'callback' => array($this, 'dateTimeLookup'),
+        'event' => 'keyup',
+        'progress' => array('type' => 'throbber', 'message' => NULL),
+      ),
+      '#required' => TRUE,
+    );
+
+    $languages = language_list();
+
+    $options = array();
+    foreach ($languages as $langcode => $data) {
+      $options[$langcode] = $data->name;
+    }
+
+    if (!empty($options)) {
+      $form['date_langcode'] = array(
+        '#title' => t('Select localizations'),
+        '#type' => 'select',
+        '#options' => $options,
+        '#multiple' => TRUE,
+        '#default_value' => '',
+      );
+    }
+
+    return $form;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate(array $form, array &$form_state) {
+    parent::validate($form, $form_state);
+
+    // The machine name field should already check to see if the requested
+    // machine name is available. Regardless of machine_name or human readable
+    // name, check to see if the provided pattern exists.
+    $format = trim($form_state['values']['date_format_pattern']);
+    $formats = $this->entityQuery
+      ->condition('pattern.' . $this->patternType, $format)
+      ->execute();
+
+    // Exclude the current format.
+    unset($formats[$this->entity->id()]);
+    if (!empty($formats)) {
+      form_set_error('date_format_pattern', t('This format already exists. Enter a unique format string.'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submit(array $form, array &$form_state) {
+    $form_state['redirect'] = 'admin/config/regional/date-time';
+    $form_state['values']['pattern'][$this->patternType] = trim($form_state['values']['date_format_pattern']);
+
+    parent::submit($form, $form_state);
+    $this->entity->save();
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/DateFormatInterface.php b/core/modules/system/lib/Drupal/system/DateFormatInterface.php
new file mode 100644
index 0000000..159b362
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/DateFormatInterface.php
@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\DateFormatInterface.
+ */
+
+namespace Drupal\system;
+
+use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Datetime\DrupalDateTime;
+
+/**
+ * @todo.
+ */
+interface DateFormatInterface extends ConfigEntityInterface {
+
+  /**
+   * @param string $type
+   *
+   * @return string
+   */
+  public function getPattern($type = DrupalDateTime::PHP);
+
+}
diff --git a/core/modules/system/lib/Drupal/system/DateFormatListController.php b/core/modules/system/lib/Drupal/system/DateFormatListController.php
new file mode 100644
index 0000000..bc86400
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/DateFormatListController.php
@@ -0,0 +1,40 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\DateFormatListController.
+ */
+
+namespace Drupal\system;
+
+use Drupal\Core\Config\Entity\ConfigEntityListController;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * @todo.
+ */
+class DateFormatListController extends ConfigEntityListController {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildHeader() {
+    $header['id'] = t('Machine name');
+    $header['label'] = t('Name');
+    $header['pattern'] = t('Pattern');
+    $header['operations'] = t('Operations');
+    return $header;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildRow(EntityInterface $entity) {
+    $row['id'] = $entity->id();
+    $row['label'] = $entity->label();
+    $row['pattern'] = format_date(REQUEST_TIME, $entity->id());
+    $row['operations']['data'] = $this->buildOperations($entity);
+    return $row;
+  }
+
+}
diff --git a/core/modules/system/lib/Drupal/system/Form/DateFormatAddForm.php b/core/modules/system/lib/Drupal/system/Form/DateFormatAddForm.php
deleted file mode 100644
index 6dec855..0000000
--- a/core/modules/system/lib/Drupal/system/Form/DateFormatAddForm.php
+++ /dev/null
@@ -1,93 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\Form\DateFormatAddForm.
- */
-
-namespace Drupal\system\Form;
-
-/**
- * Provides an add form for date formats.
- */
-class DateFormatAddForm extends DateFormatFormBase {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormID() {
-    return 'date_format_add';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, array &$form_state) {
-    form_load_include($form_state, 'admin.inc', 'system');
-    $form['date_format_name'] = array(
-      '#type' => 'textfield',
-      '#title' => 'Name',
-      '#maxlength' => 100,
-      '#description' => t('Name of the date format'),
-      '#default_value' => '',
-    );
-
-    $form['date_format_id'] = array(
-      '#type' => 'machine_name',
-      '#title' => t('Machine-readable name'),
-      '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
-      '#default_value' => '',
-      '#machine_name' => array(
-        'exists' => 'system_date_format_exists',
-        'source' => array('date_format_name'),
-      ),
-    );
-
-    if (class_exists('intlDateFormatter')) {
-      $description = t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://userguide.icu-project.org/formatparse/datetime'));
-    }
-    else {
-      $description = t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://php.net/manual/function.date.php'));
-    }
-    $form['date_format_pattern'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Format string'),
-      '#maxlength' => 100,
-      '#description' => $description,
-      '#default_value' => '',
-      '#field_suffix' => ' <small id="edit-date-format-suffix"></small>',
-      '#ajax' => array(
-        'callback' => 'system_date_time_lookup',
-        'event' => 'keyup',
-        'progress' => array('type' => 'throbber', 'message' => NULL),
-      ),
-      '#required' => TRUE,
-    );
-
-    $languages = language_list();
-
-    $options = array();
-    foreach ($languages as $langcode => $data) {
-      $options[$langcode] = $data->name;
-    }
-
-    if (!empty($options)) {
-      $form['date_langcode'] = array(
-        '#title' => t('Select localizations'),
-        '#type' => 'select',
-        '#options' => $options,
-        '#multiple' => TRUE,
-        '#default_value' => '',
-      );
-    }
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['update'] = array(
-      '#type' => 'submit',
-      '#value' => t('Add format'),
-    );
-
-    return $form;
-  }
-
-}
diff --git a/core/modules/system/lib/Drupal/system/Form/DateFormatDeleteForm.php b/core/modules/system/lib/Drupal/system/Form/DateFormatDeleteForm.php
index b56f3cf..217c281 100644
--- a/core/modules/system/lib/Drupal/system/Form/DateFormatDeleteForm.php
+++ b/core/modules/system/lib/Drupal/system/Form/DateFormatDeleteForm.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\ControllerInterface;
 use Drupal\Core\Config\ConfigFactory;
+use Drupal\system\DateFormatInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -18,20 +19,13 @@
 class DateFormatDeleteForm extends ConfirmFormBase implements ControllerInterface {
 
   /**
-   * The date format data to be deleted.
+   * The date format to be deleted.
    *
-   * @var array
+   * @var \Drupal\system\DateFormatInterface
    */
   protected $format;
 
   /**
-   * The ID of the date format to be deleted.
-   *
-   * @var string
-   */
-  protected $formatID;
-
-  /**
    * The config factory.
    *
    * @var \Drupal\Core\Config\ConfigFactory
@@ -66,8 +60,8 @@ public function getFormID() {
    */
   protected function getQuestion() {
     return t('Are you sure you want to remove the format %name : %format?', array(
-      '%name' => $this->format['name'],
-      '%format' => format_date(REQUEST_TIME, $this->formatID))
+      '%name' => $this->format->label(),
+      '%format' => format_date(REQUEST_TIME, $this->format->id()))
     );
   }
 
@@ -91,10 +85,8 @@ protected function getCancelPath() {
    * @param string $format_id
    *   The date format ID.
    */
-  public function buildForm(array $form, array &$form_state, $format_id = NULL) {
-    // We don't get the format ID in the returned format array.
-    $this->formatID = $format_id;
-    $this->format = $this->configFactory->get('system.date')->get("formats.$format_id");
+  public function buildForm(array $form, array &$form_state, DateFormatInterface $date_format = NULL) {
+    $this->format = $date_format;
 
     return parent::buildForm($form, $form_state);
   }
@@ -103,10 +95,10 @@ public function buildForm(array $form, array &$form_state, $format_id = NULL) {
    * {@inheritdoc}
    */
   public function submitForm(array &$form, array &$form_state) {
-    system_date_format_delete($this->formatID);
-    drupal_set_message(t('Removed date format %format.', array('%format' => $this->format['name'])));
+    $this->format->delete();
+    drupal_set_message(t('Removed date format %format.', array('%format' => $this->format->label())));
 
-    $form_state['redirect'] = 'admin/config/regional/date-time/formats';
+    $form_state['redirect'] = 'admin/config/regional/date-time';
   }
 
 }
diff --git a/core/modules/system/lib/Drupal/system/Form/DateFormatEditForm.php b/core/modules/system/lib/Drupal/system/Form/DateFormatEditForm.php
deleted file mode 100644
index 56afe28..0000000
--- a/core/modules/system/lib/Drupal/system/Form/DateFormatEditForm.php
+++ /dev/null
@@ -1,131 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\Form\DateFormatEditForm.
- */
-
-namespace Drupal\system\Form;
-
-use Drupal\Core\Config\ConfigFactory;
-use Drupal\Core\ControllerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides an edit form for date formats.
- */
-class DateFormatEditForm extends DateFormatFormBase implements ControllerInterface {
-
-  /**
-   * The config object.
-   *
-   * @var \Drupal\Core\Config\Config
-   */
-  protected $config;
-
-  /**
-   * Constructs a new date format form.
-   *
-   * @param \Drupal\Core\Config\ConfigFactory $config_factory
-   *   The config factory object.
-   */
-  public function __construct(ConfigFactory $config_factory) {
-    parent::__construct();
-
-    $this->config = $config_factory->get('system.date');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('config.factory')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormID() {
-    return 'date_format_edit';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, array &$form_state, $date_format_id = NULL) {
-    form_load_include($form_state, 'admin.inc', 'system');
-    $format_info = $this->config->get('formats.' . $date_format_id);
-    $pattern = $this->patternType ? $format_info['pattern'][$this->patternType] : '';
-
-    $form['date_format_name'] = array(
-      '#type' => 'textfield',
-      '#title' => 'Name',
-      '#maxlength' => 100,
-      '#description' => t('Name of the date format'),
-      '#default_value' => empty($format_info['name']) ? '' : $format_info['name']
-    );
-
-    $now = t('Displayed as %date', array('%date' => format_date(REQUEST_TIME, $date_format_id)));
-
-    $form['date_format_id'] = array(
-      '#type' => 'machine_name',
-      '#title' => t('Machine-readable name'),
-      '#description' => t('A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.'),
-      '#disabled' => !empty($date_format_id),
-      '#default_value' => $date_format_id,
-      '#machine_name' => array(
-        'exists' => 'system_date_format_exists',
-        'source' => array('date_format_name'),
-      ),
-    );
-
-    if (class_exists('intlDateFormatter')) {
-      $description = t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://userguide.icu-project.org/formatparse/datetime'));
-    }
-    else {
-      $description = t('A user-defined date format. See the <a href="@url">PHP manual</a> for available options.', array('@url' => 'http://php.net/manual/function.date.php'));
-    }
-    $form['date_format_pattern'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Format string'),
-      '#maxlength' => 100,
-      '#description' => $description,
-      '#default_value' => $pattern,
-      '#field_suffix' => ' <small id="edit-date-format-suffix">' . $now . '</small>',
-      '#ajax' => array(
-        'callback' => 'system_date_time_lookup',
-        'event' => 'keyup',
-        'progress' => array('type' => 'throbber', 'message' => NULL),
-      ),
-      '#required' => TRUE,
-    );
-
-    $languages = language_list();
-
-    $options = array();
-    foreach ($languages as $langcode => $data) {
-      $options[$langcode] = $data->name;
-    }
-
-    if (!empty($options)) {
-      $form['date_langcode'] = array(
-        '#title' => t('Select localizations'),
-        '#type' => 'select',
-        '#options' => $options,
-        '#multiple' => TRUE,
-        '#default_value' => empty($format_info['locales']) ? '' : $format_info['locales']
-      );
-    }
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['update'] = array(
-      '#type' => 'submit',
-      '#value' => t('Save format'),
-    );
-
-    return $form;
-  }
-
-}
diff --git a/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php b/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php
deleted file mode 100644
index eef17d8..0000000
--- a/core/modules/system/lib/Drupal/system/Form/DateFormatFormBase.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\system\Form\DateFormatFormBase.
- */
-
-namespace Drupal\system\Form;
-
-use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\Core\Form\FormInterface;
-use Drupal\Component\Utility\String;
-
-/**
- * Provides a base form for date formats.
- */
-abstract class DateFormatFormBase implements FormInterface {
-
-  /**
-   * The date pattern type.
-   *
-   * @var string
-   */
-  protected $patternType;
-
-  /**
-   * Constructs a new date format form.
-   */
-  public function __construct() {
-    $date = new DrupalDateTime();
-    $this->patternType = $date->canUseIntl() ? DrupalDateTime::INTL : DrupalDateTime::PHP;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, array &$form_state) {
-    $formats = system_get_date_formats();
-    $format = trim($form_state['values']['date_format_pattern']);
-
-    // The machine name field should already check to see if the requested
-    // machine name is available. Regardless of machine_name or human readable
-    // name, check to see if the provided pattern exists.
-    if (!empty($formats) && in_array($format, array_values($formats)) && (!isset($form_state['values']['date_format_id']) || $form_state['values']['date_format_id'] != $formats[$format]['date_format_id'])) {
-      form_set_error('date_format', t('This format already exists. Enter a unique format string.'));
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, array &$form_state) {
-    $format = array();
-    $format['name'] = String::checkPlain($form_state['values']['date_format_name']);
-    $format['pattern'][$this->patternType] = trim($form_state['values']['date_format_pattern']);
-    $format['locales'] = !empty($form_state['values']['date_langcode']) ? $form_state['values']['date_langcode'] : array();
-    // Formats created in the UI are not locked.
-    $format['locked'] = 0;
-
-    system_date_format_save($form_state['values']['date_format_id'], $format);
-    if (!empty($form_state['values']['date_format_id'])) {
-      drupal_set_message(t('Custom date format updated.'));
-    }
-    else {
-      drupal_set_message(t('Custom date format added.'));
-    }
-
-    $form_state['redirect'] = 'admin/config/regional/date-time/formats';
-  }
-
-}
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/DateFormat.php b/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/DateFormat.php
new file mode 100644
index 0000000..59d0330
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/DateFormat.php
@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Plugin\Core\Entity\DateFormat.
+ */
+
+namespace Drupal\system\Plugin\Core\Entity;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Datetime\DrupalDateTime;
+use Drupal\system\DateFormatInterface;
+use Drupal\Core\Entity\Annotation\EntityType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Defines the Date Format configuration entity class.
+ *
+ * @EntityType(
+ *   id = "date_format",
+ *   label = @Translation("Date format"),
+ *   module = "system",
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
+ *     "list" = "Drupal\system\DateFormatListController",
+ *     "form" = {
+ *       "add" = "Drupal\system\DateFormatAddFormController",
+ *       "edit" = "Drupal\system\DateFormatEditFormController"
+ *     }
+ *   },
+ *   config_prefix = "system.date_format",
+ *   entity_keys = {
+ *     "id" = "id",
+ *     "label" = "label",
+ *     "uuid" = "uuid"
+ *   }
+ * )
+ */
+class DateFormat extends ConfigEntityBase implements DateFormatInterface {
+
+  /**
+   * The date format machine name.
+   *
+   * @var string
+   */
+  public $id;
+
+  /**
+   * The date format UUID.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The human-readable name of the date format entity.
+   *
+   * @var string
+   */
+  public $label;
+
+  /**
+   * The date format pattern.
+   *
+   * @var array
+   */
+  public $pattern;
+
+  /**
+   * {@inheritdoc}
+   */
+  public function uri() {
+    return array(
+      'path' => 'admin/config/regional/date-time/formats/' . $this->id(),
+      'options' => array(
+        'entity_type' => $this->entityType,
+        'entity' => $this,
+      ),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getPattern($type = DrupalDateTime::PHP) {
+    return $this->pattern[$type];
+  }
+
+}
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index 2dc1c57..2f92995 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -5,12 +5,8 @@
  * Admin page callbacks for the system module.
  */
 
-use Drupal\Core\Ajax\AjaxResponse;
-use Drupal\Core\Ajax\ReplaceCommand;
-use Symfony\Component\HttpFoundation\JsonResponse;
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
-use Drupal\Core\Datetime\DrupalDateTime;
 use Drupal\system\Form\ModulesInstallConfirmForm;
 use Drupal\system\Form\ModulesUninstallConfirmForm;
 
@@ -1781,69 +1777,6 @@ function theme_system_themes_page($variables) {
 }
 
 /**
- * Displays the date format strings overview page.
- */
-function system_date_time_formats() {
-  $header = array(
-    array('data' => t('Machine name'), 'field' => 'machine_name'),
-    array('data' => t('Name'), 'field' => 'name'),
-    array('data' => t('Pattern'), 'field' => 'pattern'),
-    array('data' => t('Operations'))
-  );
-  $rows = array();
-
-  $formats = system_get_date_formats();
-
-  if (!empty($formats)) {
-    foreach ($formats as $date_format_id => $format_info) {
-      // Do not display date formats that are locked.
-      if (empty($format_info['locked'])) {
-        $row = array();
-        $row[] = array('data' => $date_format_id);
-        $row[] = array('data' => $format_info['name']);
-        $row[] = array('data' => format_date(REQUEST_TIME, $date_format_id));
-
-        // Prepare Operational links.
-        $links = array();
-        $links['edit'] = array(
-          'title' => t('Edit'),
-          'href' => 'admin/config/regional/date-time/formats/' . $date_format_id . '/edit',
-        );
-        $links['delete'] = array(
-          'title' => t('Delete'),
-          'href' => 'admin/config/regional/date-time/formats/' . $date_format_id . '/delete',
-        );
-        $row['operations'] = array('data' => array(
-          '#type' => 'operations',
-          '#links' => $links,
-        ));
-
-        $rows[] = $row;
-      }
-    }
-  }
-
-  $build['date_formats_table'] = array(
-    '#theme' => 'table',
-    '#header' => $header,
-    '#rows' => $rows,
-    '#empty' => t('No custom date formats available. <a href="@link">Add date format</a>.', array('@link' => url('admin/config/regional/date-time/formats/add'))),
-  );
-
-  return $build;
-}
-
-/**
- * Checks if the chosen machine_name exists or not.
- */
-function system_date_format_exists($candidate_machine_name) {
-  if ($formats = system_get_date_formats()) {
-    return array_key_exists($candidate_machine_name, $formats);
-  }
-  return FALSE;
-}
-
-/**
  * Page callback: Displays edit date format links for each language.
  *
  * @see locale_menu()
@@ -1900,11 +1833,11 @@ function system_date_format_localize_form($form, &$form_state, $langcode) {
   );
 
   // Get list of available formats.
-  $formats = system_get_date_formats();
+  $formats = entity_load_multiple('date_format');
   $choices = array();
   foreach ($formats as $date_format_id => $format_info) {
     // Ignore values that are localized.
-    if (empty($format_info['locales'])) {
+    if (empty($format_info->locales)) {
       $choices[$date_format_id] = format_date(REQUEST_TIME, $date_format_id);
     }
     else {
@@ -1926,7 +1859,7 @@ function system_date_format_localize_form($form, &$form_state, $langcode) {
     // Show date format select list.
     $form['date_formats']['date_format_' . $date_format_id] = array(
       '#type' => 'select',
-      '#title' => check_plain($format_info['name']),
+      '#title' => check_plain($format_info->label()),
       '#attributes' => array('class' => array('date-format')),
       '#default_value' => isset($choices[$date_format_id]) ? $date_format_id : 'custom',
       '#options' => $choices,
@@ -1943,29 +1876,13 @@ function system_date_format_localize_form($form, &$form_state, $langcode) {
 }
 
 /**
- * Ajax callback; Returns the date for a given format string.
- */
-function system_date_time_lookup($form, &$form_state) {
-  $format = '';
-  if (!empty($form_state['values']['date_format_pattern'])) {
-    $format = t('Displayed as %date_format', array('%date_format' => format_date(REQUEST_TIME, 'custom', $form_state['values']['date_format_pattern'])));
-  }
-  // Return a command instead of a string, since the Ajax framework
-  // automatically prepends an additional empty DIV element for a string, which
-  // breaks the layout.
-  $response = new AjaxResponse();
-  $response->addCommand(new ReplaceCommand('#edit-date-format-suffix', '<small id="edit-date-format-suffix">' . $format . '</small>'));
-  return $response;
-}
-
-/**
  * Form submission handler for system_date_format_localize_form().
  */
 function system_date_format_localize_form_submit($form, &$form_state) {
   $langcode = $form_state['values']['langcode'];
 
-  $formats = system_get_date_formats();
-  foreach ($formats as $date_format_id => $format_info) {
+  $formats = Drupal::entityQuery('date_format')->execute();
+  foreach ($formats as $date_format_id) {
     if (isset($form_state['values']['date_format_' . $date_format_id])) {
       $format = $form_state['values']['date_format_' . $date_format_id];
       system_date_format_localize_form_save($langcode, $date_format_id, $formats[$format]['pattern']);
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 2c70d82..61bf3ce 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -867,10 +867,8 @@ function system_menu() {
   $items['admin/config/regional/date-time'] = array(
     'title' => 'Date and time formats',
     'description' => 'Configure display format strings for date and time.',
-    'page callback' => 'system_date_time_formats',
-    'access arguments' => array('administer site configuration'),
+    'route_name' => 'date_format_list',
     'weight' => -9,
-    'file' => 'system.admin.inc',
   );
   $items['admin/config/regional/date-time/formats/add'] = array(
     'title' => 'Add format',
@@ -892,13 +890,6 @@ function system_menu() {
     'description' => 'Allow users to delete a configured date format.',
     'route_name' => 'date_format_delete',
   );
-  $items['admin/config/regional/date-time/formats/lookup'] = array(
-    'title' => 'Date and time lookup',
-    'page callback' => 'system_date_time_lookup',
-    'access arguments' => array('administer site configuration'),
-    'type' => MENU_CALLBACK,
-    'file' => 'system.admin.inc',
-  );
 
   // Search settings.
   $items['admin/config/search'] = array(
@@ -3692,22 +3683,6 @@ function system_run_automated_cron() {
 }
 
 /**
- * Gets the list of defined date formats and attributes.
- *
- * @return array
- *   An associative array of date formats. The top-level keys are the
- *   machine-readable names of the date formats. The values are associative
- *   arrays with the following keys:
- *   - name: The string human readable name of the date format.
- *   - pattern: An associative array of patterns that will modify the format
- *     of the date, keyed with 'php' for normal PHP date pattern and 'intl'
- *     for the alternate pattern used by the IntlDateFormatter.
- */
-function system_get_date_formats() {
-  return config('system.date')->get('formats');
-}
-
-/**
  * Gets the appropriate date format string for a date type and locale.
  *
  * @param $langcode
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index f39cf3b..b817d10 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -74,22 +74,30 @@ system_site_maintenance_mode:
   requirements:
     _permission: 'administer site configuration'
 
+date_format_list:
+  pattern: '/admin/config/regional/date-time'
+  defaults:
+    _content: '\Drupal\Core\Entity\Controller\EntityListController::listing'
+    entity_type: 'date_format'
+  requirements:
+    _permission: 'administer site configuration'
+
 date_format_add:
   pattern: '/admin/config/regional/date-time/formats/add'
   defaults:
-    _form: '\Drupal\system\Form\DateFormatAddForm'
+    _entity_form: 'date_format.add'
   requirements:
     _permission: 'administer site configuration'
 
 date_format_edit:
-  pattern: '/admin/config/regional/date-time/formats/{date_format_id}/edit'
+  pattern: '/admin/config/regional/date-time/formats/{date_format}/edit'
   defaults:
-    _form: '\Drupal\system\Form\DateFormatEditForm'
+    _entity_form: 'date_format.edit'
   requirements:
     _permission: 'administer site configuration'
 
 date_format_delete:
-  pattern: 'admin/config/regional/date-time/formats/{format_id}/delete'
+  pattern: 'admin/config/regional/date-time/formats/{date_format}/delete'
   defaults:
     _form: '\Drupal\system\Form\DateFormatDeleteForm'
   requirements:
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/field/Date.php b/core/modules/views/lib/Drupal/views/Plugin/views/field/Date.php
index 9fa6d62..5fc1e9a 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/field/Date.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/field/Date.php
@@ -31,9 +31,9 @@ protected function defineOptions() {
   public function buildOptionsForm(&$form, &$form_state) {
 
     $date_formats = array();
-    $date_types = system_get_date_formats();
+    $date_types = entity_load_multiple('date_format');
     foreach ($date_types as $machine_name => $value) {
-      $date_formats[$machine_name] = t('@name format: @date', array('@name' => $value['name'], '@date' => format_date(REQUEST_TIME, $machine_name)));
+      $date_formats[$machine_name] = t('@name format: @date', array('@name' => $value->label(), '@date' => format_date(REQUEST_TIME, $machine_name)));
     }
 
     $form['date_format'] = array(
