diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index e9fb855..bd7590a 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -120,27 +120,6 @@
  *       - access callback: As in hook_menu(). 'user_access' will be assumed if
  *         no value is provided.
  *       - access arguments: As in hook_menu().
- *   - view modes: An array describing the view modes for the entity type. View
- *     modes let entities be displayed differently depending on the context.
- *     For instance, a node can be displayed differently on its own page
- *     ('full' mode), on the home page or taxonomy listings ('teaser' mode), or
- *     in an RSS feed ('rss' mode). Modules taking part in the display of the
- *     entity (notably the Field API) can adjust their behavior depending on
- *     the requested view mode. An additional 'default' view mode is available
- *     for all entity types. This view mode is not intended for actual entity
- *     display, but holds default display settings. For each available view
- *     mode, administrators can configure whether it should use its own set of
- *     field display settings, or just replicate the settings of the 'default'
- *     view mode, thus reducing the amount of display configurations to keep
- *     track of. Keys of the array are view mode names. Each view mode is
- *     described by an array with the following key/value pairs:
- *     - label: The human-readable name of the view mode
- *     - custom settings: A boolean specifying whether the view mode should by
- *       default use its own custom field display settings. If FALSE, entities
- *       displayed in this view mode will reuse the 'default' display settings
- *       by default (e.g. right after the module exposing the view mode is
- *       enabled), but administrators can later use the Field UI to apply custom
- *       display settings specific to the view mode.
  *
  * @see entity_load()
  * @see entity_load_multiple()
@@ -172,20 +151,6 @@ function hook_entity_info() {
         'bundle' => 'type',
       ),
       'bundles' => array(),
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full content'),
-          'custom settings' => FALSE,
-        ),
-        'teaser' => array(
-          'label' => t('Teaser'),
-          'custom settings' => TRUE,
-        ),
-        'rss' => array(
-          'label' => t('RSS'),
-          'custom settings' => FALSE,
-        ),
-      ),
     ),
   );
 
diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 48ee728..8956fd8 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -64,11 +64,6 @@ function entity_get_info($entity_type = NULL) {
           'revision' => '',
           'bundle' => '',
         );
-        foreach ($entity_info[$name]['view modes'] as $view_mode => $view_mode_info) {
-          $entity_info[$name]['view modes'][$view_mode] += array(
-            'custom settings' => FALSE,
-          );
-        }
         // If no bundle key is provided, assume a single bundle, named after
         // the entity type.
         if (empty($entity_info[$name]['entity keys']['bundle']) && empty($entity_info[$name]['bundles'])) {
@@ -83,6 +78,17 @@ function entity_get_info($entity_type = NULL) {
           }
         }
       }
+
+      // Add view modes.
+      foreach (entity_load_multiple('view_mode') as $view_mode) {
+        if (isset($entity_info[$view_mode->type])) {
+          $entity_info[$view_mode->type]['view modes'][$view_mode->name()] = array(
+            'label' => check_plain($view_mode->label()),
+            'custom settings' => $view_mode->custom,
+          );
+        }
+      }
+
       // Let other modules alter the entity info.
       drupal_alter('entity_info', $entity_info);
       cache()->set("entity_info:$langcode", $entity_info, CacheBackendInterface::CACHE_PERMANENT, array('entity_info' => TRUE));
diff --git a/core/lib/Drupal/Core/Entity/ViewMode/EntityViewMode.php b/core/lib/Drupal/Core/Entity/ViewMode/EntityViewMode.php
new file mode 100644
index 0000000..a4125dd
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/ViewMode/EntityViewMode.php
@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\Core\Entity\ViewMode\EntityViewMode.
+ */
+
+namespace Drupal\Core\Entity\ViewMode;
+
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+
+/**
+ * Defines the view mode configuration entity class.
+ */
+class EntityViewMode extends ConfigEntityBase {
+
+  /**
+   * The machine name of the view mode.
+   *
+   * @var string
+   */
+  public $machine_name;
+
+  /**
+   * The UUID of the view mode.
+   *
+   * @var string
+   */
+  public $uuid;
+
+  /**
+   * The view mode label.
+   *
+   * @var string
+   */
+  public $name;
+
+  /**
+   * The entity type this view mode is used for.
+   *
+   * @var string
+   */
+  public $type;
+
+  /**
+   * Whether or not this view mode has custom settings in the Field UI.
+   *
+   * @var bool
+   */
+  public $custom = FALSE;
+
+  /**
+   * Whether or not this view mode can be removed.
+   *
+   * @var bool
+   */
+  public $locked = FALSE;
+
+  /**
+   * Overrides Drupal\Core\Core\Entity\Entity::id().
+   */
+  public function id() {
+    return $this->machine_name;
+  }
+
+  /**
+   * Returns the raw view mode name, exluding the entity type.
+   *
+   * @return string
+   *   The raw view mode name.
+   */
+  public function name() {
+    $name = strtok($this->machine_name, '.');
+    return strtok('.');
+  }
+
+  /**
+   * Overrides Drupal\Core\Core\Entity\Entity::uri().
+   */
+  public function uri() {
+    return array(
+      'path' => 'admin/config/system/view-modes/' . $this->id(),
+      'options' => array(
+        'entity_type' => $this->entityType,
+        'entity' => $this,
+      ),
+    );
+  }
+
+}
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 7c43e28..d24b9ee 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -249,19 +249,6 @@ function book_admin_paths() {
 }
 
 /**
- * Implements hook_entity_info_alter().
- */
-function book_entity_info_alter(&$info) {
-  // Add the 'Print' view mode for nodes.
-  $info['node']['view modes'] += array(
-    'print' => array(
-      'label' => t('Print'),
-      'custom settings' => FALSE,
-    ),
-  );
-}
-
-/**
  * Implements hook_block_info().
  */
 function book_block_info() {
diff --git a/core/modules/book/config/view_mode.node.print.yml b/core/modules/book/config/view_mode.node.print.yml
new file mode 100644
index 0000000..1ed8183
--- /dev/null
+++ b/core/modules/book/config/view_mode.node.print.yml
@@ -0,0 +1,5 @@
+machine_name: node.print
+name: Print
+custom: '0'
+type: node
+locked: '1'
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index df0a33a..f628422 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -120,12 +120,6 @@ function comment_entity_info() {
       ),
       'bundles' => array(),
       'render controller class' => 'Drupal\comment\CommentRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full comment'),
-          'custom settings' => FALSE,
-        ),
-      ),
       'static cache' => FALSE,
     ),
   );
diff --git a/core/modules/comment/config/view_mode.comment.full.yml b/core/modules/comment/config/view_mode.comment.full.yml
new file mode 100644
index 0000000..43b6233
--- /dev/null
+++ b/core/modules/comment/config/view_mode.comment.full.yml
@@ -0,0 +1,5 @@
+machine_name: comment.full
+name: Full comment
+custom: '0'
+type: comment
+locked: '1'
diff --git a/core/modules/entity_ui/css/entity_ui.admin.css b/core/modules/entity_ui/css/entity_ui.admin.css
new file mode 100644
index 0000000..53093a1
--- /dev/null
+++ b/core/modules/entity_ui/css/entity_ui.admin.css
@@ -0,0 +1,15 @@
+/**
+ * @file
+ * Stylesheet for the administration pages of the Entity UI module.
+ */
+
+.operations {
+  width: 100px;
+}
+
+table caption {
+  font-size: 110%;
+  font-weight: bold;
+  text-align: left;
+  padding-bottom: 0.5em;
+}
diff --git a/core/modules/entity_ui/entity_ui.admin.inc b/core/modules/entity_ui/entity_ui.admin.inc
new file mode 100644
index 0000000..af636cd
--- /dev/null
+++ b/core/modules/entity_ui/entity_ui.admin.inc
@@ -0,0 +1,66 @@
+<?php
+
+/**
+ * @file
+ * Administrative functions for view modes.
+ */
+
+/**
+ * Menu callback: list all view modes.
+ */
+function entity_ui_view_mode_list() {
+  $build = array();
+  $weight = 0;
+  $controller = entity_list_controller('view_mode');
+  foreach (entity_get_info() as $type => $info) {
+    if ($type != 'view_mode' && !empty($info['fieldable'])) {
+      $build[$type] = $controller->set($type)->render();
+      // Content is usually the most important entity type in the system.
+      $build[$type]['#weight'] = ($type == 'node') ? -10 : $weight++;
+    }
+  }
+  $build['#attached']['css'][] = drupal_get_path('module', 'entity_ui') . '/css/entity_ui.admin.css';
+  return $build;
+}
+
+/**
+ * Menu callback: view mode edit form.
+ */
+function entity_ui_view_mode_add($type) {
+  $view_mode = entity_create('view_mode', array('type' => $type));
+  return entity_get_form($view_mode);
+}
+
+/**
+ * Menu callback: view mode delete confirm form.
+ */
+function entity_ui_view_mode_delete_form($form, $form_state, $view_mode) {
+  $form['#view_mode'] = $view_mode;
+
+  $form['name'] = array(
+    '#type' => 'value',
+    '#value' => $view_mode->id(),
+  );
+
+  return confirm_form(
+    $form,
+    t('Are you sure you want to delete the %view-mode view mode?', array(
+      '%view-mode' => $view_mode->label(),
+    )),
+    'admin/config/system/view-modes',
+    t('Deleting a view mode will cause any output still requesting to use that view mode to use the default display settings.'),
+    t('Delete'),
+    t('Cancel')
+  );
+}
+
+/**
+ * Submit handler: delete a view mode.
+ */
+function entity_ui_view_mode_delete_form_submit($form, &$form_state) {
+  drupal_set_message(t('Deleted the %view-mode view mode.', array(
+    '%view-mode' => $form['#view_mode']->label(),
+  )));
+  $form['#view_mode']->delete();
+  $form_state['redirect'] = 'admin/config/system/view-modes';
+}
diff --git a/core/modules/entity_ui/entity_ui.info b/core/modules/entity_ui/entity_ui.info
new file mode 100644
index 0000000..9d2b59c
--- /dev/null
+++ b/core/modules/entity_ui/entity_ui.info
@@ -0,0 +1,6 @@
+name = Entity UI
+description = User interface for the Entity API.
+package = Core
+version = VERSION
+core = 8.x
+configure = admin/config/system/view-modes
diff --git a/core/modules/entity_ui/entity_ui.module b/core/modules/entity_ui/entity_ui.module
new file mode 100644
index 0000000..a43695a
--- /dev/null
+++ b/core/modules/entity_ui/entity_ui.module
@@ -0,0 +1,120 @@
+<?php
+
+/**
+ * @file
+ * Provides a user interface for the Entity API.
+ */
+
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Implements hook_help().
+ */
+function entity_ui_help($path, $arg) {
+  switch ($path) {
+    case 'admin/help#entity_ui':
+      $output = '';
+      $output .= '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t("View modes allow you to display and manipulate pieces of content (entities) on your site depending on their context. You're probably familiar with the default Drupal view modes 'full content' and 'teaser', and configuring field visibility, formatters, and template files for each. Any number of custom view modes can be created for each entity type through the view mode administration page, allowing for a very flexible system of configurable contextual display.") . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<p>' . t("@todo") . '</p>';
+      $output .= '<h3>' . t('Creating custom view modes') . '</h3>';
+      $output .= '<p>' . t("@todo") . '</p>';
+      $output .= '<h3>' . t("Managing an entity's display with view modes") . '</h3>';
+      $output .= '<p>' . t("@todo") . '</p>';
+      $output .= '<h3>' . t('Using view modes in template files') . '</h3>';
+      $output .= '<p>' . t("@todo") . '</p>';
+      return $output;
+
+    case 'admin/config/system/view-modes':
+      return '<p>' . t("View modes allow entities to be displayed and manipulated depending on their context. A common example is configuring different field visibility, formatters, and template files for a content type's teaser and full content view modes.") . '</p>';
+
+  }
+}
+
+/**
+ * Implements hook_permission().
+ */
+function entity_ui_permission() {
+  return array(
+    'administer view modes' => array(
+      'title' => t('Add, edit and delete view modes.'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_entity_info_alter().
+ */
+function entity_ui_entity_info_alter(&$entity_info) {
+  // Add a list and form controller for the view mode entity type.
+  $entity_info['view_mode']['list controller class'] = 'Drupal\entity_ui\ViewModeListController';
+  $entity_info['view_mode']['form controller class'] = array(
+    'default' => 'Drupal\entity_ui\ViewModeFormController',
+  );
+}
+
+/**
+ * Implements hook_menu().
+ */
+function entity_ui_menu() {
+  $items['admin/config/system/view-modes'] = array(
+    'title' => 'View modes',
+    'description' => 'Create and manage view modes for displaying content in different contexts.',
+    'page callback' => 'entity_ui_view_mode_list',
+    'access arguments' => array('administer view modes'),
+    'file' => 'entity_ui.admin.inc',
+  );
+  $items['admin/config/system/view-modes/add/%'] = array(
+    'title' => 'Add view mode',
+    'page callback' => 'entity_ui_view_mode_add',
+    'page arguments' => array(5),
+    'access arguments' => array('administer view modes'),
+    'file' => 'entity_ui.admin.inc',
+  );
+  $items['admin/config/system/view-modes/%view_mode/edit'] = array(
+    'title' => 'Edit view mode',
+    'page callback' => 'entity_get_form',
+    'page arguments' => array(4),
+    'access arguments' => array('administer view modes'),
+  );
+  $items['admin/config/system/view-modes/%view_mode/delete'] = array(
+    'title' => 'Delete view mode',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('entity_ui_view_mode_delete_form', 4),
+    'access arguments' => array('administer view modes'),
+    'file' => 'entity_ui.admin.inc',
+  );
+
+  return $items;
+}
+
+/**
+ * Loads a view mode by machine name.
+ */
+function view_mode_load($machine_name) {
+  return entity_load('view_mode', $machine_name);
+}
+
+/**
+ * Checks for an existing view mode.
+ */
+function entity_ui_view_mode_exists($machine_name, $element) {
+  return entity_load('view_mode', $element['#entity_type'] . ".$machine_name");
+}
+
+/**
+ * Implements hook_view_mode_presave().
+ */
+function entity_ui_view_mode_presave(EntityInterface $entity) {
+  entity_info_cache_clear();
+  state()->set('menu_rebuild_needed', TRUE);
+}
+
+/**
+ * Implements hook_view_mode_delete().
+ */
+function entity_ui_view_mode_delete(EntityInterface $entity) {
+  entity_info_cache_clear();
+  state()->set('menu_rebuild_needed', TRUE);
+}
diff --git a/core/modules/entity_ui/lib/Drupal/entity_ui/Tests/ViewModeTest.php b/core/modules/entity_ui/lib/Drupal/entity_ui/Tests/ViewModeTest.php
new file mode 100644
index 0000000..5114d91
--- /dev/null
+++ b/core/modules/entity_ui/lib/Drupal/entity_ui/Tests/ViewModeTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\entity_ui\Tests\ViewModeTest.
+ */
+
+namespace Drupal\entity_ui\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests managing of view modes.
+ */
+class ViewModeTest extends WebTestBase {
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('field_ui', 'entity_ui');
+
+  public static function getInfo() {
+    return array(
+      'name' => 'View modes',
+      'description' => 'Tests for managing view modes.',
+      'group' => 'Entity UI',
+    );
+  }
+
+  function setUp() {
+    parent::setUp();
+
+    $this->drupalLogin($this->drupalCreateUser(array('administer content types', 'administer users', 'administer view modes', 'access administration pages')));
+    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
+  }
+
+  /**
+   * Tests managing view modes.
+   */
+  function testManageViewModes() {
+    $edit = array(
+      'name' => 'Testing',
+      'machine_name' => 'testing',
+    );
+    $this->drupalPost('admin/config/system/view-modes/add/node', $edit, t('Save'));
+    $this->assertText(format_string('Saved the !name view mode.', array('!name' => $edit['name'])));
+
+    // Create the same and assert it already exists.
+    $this->drupalPost('admin/config/system/view-modes/add/node', $edit, t('Save'));
+    $this->assertText('The machine-readable name is already in use. It must be unique.', 'View mode testing already exists.');
+
+    // Assert it's found on the Field UI for article.
+    $this->drupalGet('admin/structure/types/manage/article/display');
+    $this->assertRaw('view_modes_custom[testing]', 'Testing view mode found on node article.');
+
+    // Assert it's not found on the Field UI for user.
+    $this->drupalGet('admin/config/people/accounts/display');
+    $this->assertNoRaw('view_modes_custom[testing]', 'Testing view mode not found on user.');
+
+    // Update view mode label.
+    $edit = array(
+      'name' => 'Testing 2',
+    );
+    $this->drupalPost('admin/config/system/view-modes/node.testing/edit', $edit, t('Save'));
+    $this->assertText('Saved the Testing 2 view mode.', 'Testing label updated.');
+
+    // Remove a view mode.
+    $this->drupalPost('admin/config/system/view-modes/node.testing/delete', array(), t('Delete'));
+    $this->assertText('Deleted the Testing 2 view mode', 'Deleted the Testing view mode.');
+
+    // Assert the view mode is gone at the manage display screen.
+    $this->drupalGet('admin/structure/types/manage/article/display');
+    $this->assertNoRaw('view_modes_custom[testing]', 'Testing view mode not found on node article.');
+  }
+
+}
diff --git a/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeFormController.php b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeFormController.php
new file mode 100644
index 0000000..5fd192c
--- /dev/null
+++ b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeFormController.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\entity_ui\ViewModeFormController.
+ */
+
+namespace Drupal\entity_ui;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the view mode forms.
+ */
+class ViewModeFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state, EntityInterface $view_mode) {
+    $entity_info = entity_get_info($view_mode->type);
+    $form['type'] = array(
+      '#type' => 'item',
+      '#title' => t('Entity type'),
+      '#markup' => check_plain($entity_info['label']),
+    );
+    $form['name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Name'),
+      '#default_value' => $view_mode->label(),
+      '#required' => TRUE,
+    );
+
+    $form['machine_name'] = array(
+      '#type' => 'machine_name',
+      '#machine_name' => array(
+        'source' => array('name'),
+        'exists' => 'entity_ui_view_mode_exists',
+      ),
+      '#entity_type' => $view_mode->type,
+      '#default_value' => $view_mode->name(),
+      '#disabled' => !$view_mode->isNew(),
+      '#field_prefix' => "$view_mode->type.",
+    );
+
+    return $form;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::actions().
+   */
+  protected function actions(array $form, array &$form_state) {
+    $view_mode = $this->getEntity($form_state);
+    $actions = parent::actions($form, $form_state);
+    $actions['delete']['#access'] = !$view_mode->locked;
+    return $actions;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::validate().
+   */
+  public function validate(array $form, array &$form_state) {
+    $entity = clone $this->getEntity($form_state);
+    form_set_value($form['machine_name'], $entity->type . '.' . $form_state['values']['machine_name'], $form_state);
+    parent::validate($form, $form_state);
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   *
+   * @todo Move this code to the base controller: http://drupal.org/node/1728786
+   */
+  public function save(array $form, array &$form_state) {
+    $view_mode = $this->getEntity($form_state);
+    $view_mode->save();
+    drupal_set_message(t('Saved the %view-mode view mode.', array(
+      '%view-mode' => $view_mode->label(),
+    )));
+
+    $form_state['redirect'] = 'admin/config/system/view-modes';
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::delete().
+   *
+   * @todo Move this code to the base controller: http://drupal.org/node/1728786
+   */
+  public function delete(array $form, array &$form_state) {
+    $destination = array();
+    if (isset($_GET['destination'])) {
+      $destination = drupal_get_destination();
+      unset($_GET['destination']);
+    }
+    $view_mode = $this->getEntity($form_state);
+    $form_state['redirect'] = array('admin/config/system/view-modes/' . $view_mode->id() . '/delete', array('query' => $destination));
+  }
+
+}
diff --git a/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeListController.php b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeListController.php
new file mode 100644
index 0000000..f612d91
--- /dev/null
+++ b/core/modules/entity_ui/lib/Drupal/entity_ui/ViewModeListController.php
@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\entity_ui\ViewModeListController.
+ */
+
+namespace Drupal\entity_ui;
+
+use Drupal\Core\Config\Entity\ConfigEntityListController;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Provides a listing of view modes.
+ */
+class ViewModeListController extends ConfigEntityListController {
+
+  protected $type;
+
+  public function set($type) {
+    $this->type = entity_get_info($type);
+    $this->type['type'] = $type;
+    return $this;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::load().
+   */
+  public function load() {
+    $type = $this->type['type'];
+    return array_filter(parent::load(), function ($entity) use ($type) {
+      return $entity->type == $type;
+    });
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildHeader();
+   */
+  public function buildHeader() {
+    $header['name'] = t('Name');
+    $header['operations'] = t('Operations');
+    return $header;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildRow();
+   */
+  public function buildRow(EntityInterface $view_mode) {
+    $row['name'] = check_plain($view_mode->label());
+    $row['operations']['data'] = $this->buildOperations($view_mode);
+    $row['operations']['class'] = array('operations');
+    return $row;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::getOperations();
+   */
+  public function getOperations(EntityInterface $view_mode) {
+    $operations = parent::getOperations($view_mode);
+    if ($view_mode->locked) {
+      unset($operations['delete']);
+    }
+    return $operations;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityListController::buildRow();
+   */
+  public function render() {
+    $build = parent::render();
+    $build['#rows']['_add_new'][] = array(
+      'data' => array(
+        '#type' => 'link',
+        '#href' => 'admin/config/system/view-modes/add/' . $this->type['type'],
+        '#title' => t('Add new %type view mode', array('%type' => $this->type['label'])),
+        '#options' => array(
+          'html' => TRUE,
+        ),
+      ),
+      'colspan' => count($build['#header']),
+    );
+    $build['#caption'] = check_plain($this->type['label']);
+    return $build;
+  }
+
+}
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 0e92ef0..87c7a50 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -1,9 +1,12 @@
 <?php
+
 /**
  * @file
  * Allows administrators to attach custom fields to fieldable types.
  */
 
+use Drupal\Core\Entity\EntityInterface;
+
 /**
  * Implements hook_help().
  */
diff --git a/core/modules/file/config/view_mode.file.full.yml b/core/modules/file/config/view_mode.file.full.yml
new file mode 100644
index 0000000..4746580
--- /dev/null
+++ b/core/modules/file/config/view_mode.file.full.yml
@@ -0,0 +1,5 @@
+machine_name: file.full
+name: File default
+custom: '0'
+type: file
+locked: '1'
diff --git a/core/modules/file/file.module b/core/modules/file/file.module
index 4e6c8eb..c008cb3 100644
--- a/core/modules/file/file.module
+++ b/core/modules/file/file.module
@@ -102,12 +102,6 @@ function file_entity_info() {
         'label' => 'filename',
         'uuid' => 'uuid',
       ),
-      'view modes' => array(
-        'full' => array(
-          'label' => t('File default'),
-          'custom settings' => FALSE,
-        ),
-      ),
       'static cache' => FALSE,
     ),
   );
diff --git a/core/modules/node/config/view_mode.node.full.yml b/core/modules/node/config/view_mode.node.full.yml
new file mode 100644
index 0000000..0e667c5
--- /dev/null
+++ b/core/modules/node/config/view_mode.node.full.yml
@@ -0,0 +1,5 @@
+machine_name: node.full
+name: Full content
+custom: '0'
+type: node
+locked: '1'
diff --git a/core/modules/node/config/view_mode.node.rss.yml b/core/modules/node/config/view_mode.node.rss.yml
new file mode 100644
index 0000000..7b36134
--- /dev/null
+++ b/core/modules/node/config/view_mode.node.rss.yml
@@ -0,0 +1,5 @@
+machine_name: node.rss
+name: RSS
+custom: '0'
+type: node
+locked: '1'
diff --git a/core/modules/node/config/view_mode.node.teaser.yml b/core/modules/node/config/view_mode.node.teaser.yml
new file mode 100644
index 0000000..63efd07
--- /dev/null
+++ b/core/modules/node/config/view_mode.node.teaser.yml
@@ -0,0 +1,5 @@
+machine_name: node.teaser
+name: Teaser
+custom: '1'
+type: node
+locked: '1'
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 55989de..ae33873 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -218,20 +218,6 @@ function node_entity_info() {
       ),
       'bundles' => array(),
       'render controller class' => 'Drupal\node\NodeRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('Full content'),
-          'custom settings' => FALSE,
-        ),
-        'teaser' => array(
-          'label' => t('Teaser'),
-          'custom settings' => TRUE,
-        ),
-        'rss' => array(
-          'label' => t('RSS'),
-          'custom settings' => FALSE,
-        ),
-      ),
     ),
   );
 
@@ -240,21 +226,6 @@ function node_entity_info() {
     $return['node']['translation']['node'] = TRUE;
   }
 
-  // Search integration is provided by node.module, so search-related
-  // view modes for nodes are defined here and not in search.module.
-  if (module_exists('search')) {
-    $return['node']['view modes'] += array(
-      'search_index' => array(
-        'label' => t('Search index'),
-        'custom settings' => FALSE,
-      ),
-      'search_result' => array(
-        'label' => t('Search result'),
-        'custom settings' => FALSE,
-      ),
-    );
-  }
-
   // Bundles must provide a human readable name so we can create help and error
   // messages, and the path to attach Field admin pages to.
   node_type_cache_reset();
diff --git a/core/modules/search/config/view_mode.node.search_index.yml b/core/modules/search/config/view_mode.node.search_index.yml
new file mode 100644
index 0000000..0324aba
--- /dev/null
+++ b/core/modules/search/config/view_mode.node.search_index.yml
@@ -0,0 +1,5 @@
+machine_name: node.search_index
+name: Search index
+custom: '0'
+type: node
+locked: '1'
diff --git a/core/modules/search/config/view_mode.node.search_result.yml b/core/modules/search/config/view_mode.node.search_result.yml
new file mode 100644
index 0000000..da28216
--- /dev/null
+++ b/core/modules/search/config/view_mode.node.search_result.yml
@@ -0,0 +1,5 @@
+machine_name: node.search_result
+name: Search result
+custom: '0'
+type: node
+locked: '1'
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
index da4034b..654bea7 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
@@ -86,5 +86,13 @@ public function testFilledStandardUpgrade() {
     $blog_type = node_type_load('blog');
     $this->assertEqual($blog_type->module, 'node', "Content type 'blog' has been reassigned from the blog module to the node module.");
     $this->assertEqual($blog_type->base, 'node_content', "The base string used to construct callbacks corresponding to content type 'Blog' has been reassigned to 'node_content'.");
+
+    // Verify all core view modes have been converted to config.
+    $entity_info = entity_get_info();
+    foreach ($entity_info as $type => $info) {
+      if (!empty($info['fieldable'])) {
+        $this->assertTrue(!empty($info['view modes']), format_string('View modes for @entity_type have been converted', array('@entity_type' => $info['label'])));
+      }
+    }
   }
 }
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index d0deae1..9f6c28a 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -2188,6 +2188,51 @@ function system_update_8030() {
 }
 
 /**
+ * Moves entity view modes to config.
+ *
+ * @ingroup config_upgrade
+ */
+function system_update_8031() {
+  // We can't call entity_info() in an update hook, so we hardcode them.
+  // We only care about the core view modes as hook_entity_info_alter() will
+  // still work since that was the only way to add custom view modes in D7.
+  $entity_view_modes = array(
+    'node' => array(
+      'full' => 'Full content',
+      'teaser' => 'Teaser',
+      'rss' => 'RSS',
+      'search_index' => 'Search index',
+      'search_result' => 'Search result',
+      'print' => 'Print',
+    ),
+    'file' => array(
+      'full' => 'File default',
+    ),
+    'comment' => array(
+      'full' => 'Full comment',
+    ),
+    'user' => array(
+      'full' => 'User account',
+    ),
+    'taxonomy_term' => array(
+      'full' => 'Taxonomy term page',
+    ),
+  );
+
+  foreach ($entity_view_modes as $entity_type => $view_modes) {
+    foreach ($view_modes as $key => $name) {
+      config('view_mode.' . $entity_type . '.' . $key)
+        ->set('machine_name', $entity_type . '.' . $key)
+        ->set('name', $name)
+        ->set('type', $entity_type)
+        ->set('locked', TRUE)
+        ->set('custom', FALSE)
+        ->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/system.module b/core/modules/system/system.module
index ea3dadc..2a1809b 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -1079,6 +1079,30 @@ function system_menu() {
 }
 
 /**
+ * Implements hook_entity_info().
+ */
+function system_entity_info() {
+  // This entity type is provided on behalf of the entity system.
+  // @todo Remove from system module after http://drupal.org/node/1763974.
+  $return = array(
+    'view_mode' => array(
+      'label' => t('View mode'),
+      'entity class' => 'Drupal\Core\Entity\ViewMode\EntityViewMode',
+      'controller class' => 'Drupal\Core\Config\Entity\ConfigStorageController',
+      'config prefix' => 'view_mode',
+      'fieldable' => FALSE,
+      'entity keys' => array(
+        'id' => 'machine_name',
+        'label' => 'name',
+        'uuid' => 'uuid',
+      ),
+    ),
+  );
+
+  return $return;
+}
+
+/**
  * Page callback; Execute cron tasks.
  *
  * @see system_cron_access().
diff --git a/core/modules/taxonomy/config/view_mode.taxonomy_term.full.yml b/core/modules/taxonomy/config/view_mode.taxonomy_term.full.yml
new file mode 100644
index 0000000..99dca2d
--- /dev/null
+++ b/core/modules/taxonomy/config/view_mode.taxonomy_term.full.yml
@@ -0,0 +1,5 @@
+machine_name: taxonomy_term.full
+name: Taxonomy term page
+custom: '0'
+type: taxonomy_term
+locked: '1'
diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module
index 874c78a..3d142b5 100644
--- a/core/modules/taxonomy/taxonomy.module
+++ b/core/modules/taxonomy/taxonomy.module
@@ -131,13 +131,6 @@ function taxonomy_entity_info() {
       ),
       'bundles' => array(),
       'render controller class' => 'Drupal\taxonomy\TermRenderController',
-      'view modes' => array(
-        // @todo View mode for display as a field (when attached to nodes etc).
-        'full' => array(
-          'label' => t('Taxonomy term page'),
-          'custom settings' => FALSE,
-        ),
-      ),
     ),
   );
   foreach (taxonomy_vocabulary_get_names() as $machine_name => $vocabulary) {
@@ -164,12 +157,6 @@ function taxonomy_entity_info() {
       'label' => 'name',
     ),
     'fieldable' => FALSE,
-    'view modes' => array(
-      'full' => array(
-        'label' => t('Taxonomy vocabulary default'),
-        'custom settings' => FALSE,
-      ),
-    ),
   );
 
   return $return;
diff --git a/core/modules/user/config/view_mode.user.full.yml b/core/modules/user/config/view_mode.user.full.yml
new file mode 100644
index 0000000..283935e
--- /dev/null
+++ b/core/modules/user/config/view_mode.user.full.yml
@@ -0,0 +1,5 @@
+machine_name: user.full
+name: User account
+custom: '0'
+type: user
+locked: '1'
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index c064427..454afd5 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -169,12 +169,6 @@ function user_entity_info() {
         ),
       ),
       'render controller class' => 'Drupal\user\UserRenderController',
-      'view modes' => array(
-        'full' => array(
-          'label' => t('User account'),
-          'custom settings' => FALSE,
-        ),
-      ),
     ),
   );
 }
diff --git a/core/profiles/standard/standard.info b/core/profiles/standard/standard.info
index 8b8a33b..28db9c6 100644
--- a/core/profiles/standard/standard.info
+++ b/core/profiles/standard/standard.info
@@ -22,3 +22,4 @@ dependencies[] = overlay
 dependencies[] = field_ui
 dependencies[] = file
 dependencies[] = rdf
+dependencies[] = entity_ui
