diff --git a/core/INSTALL.txt b/core/INSTALL.txt
index a5c41ce..63561a4 100644
--- a/core/INSTALL.txt
+++ b/core/INSTALL.txt
@@ -7,7 +7,6 @@ CONTENTS OF THIS FILE
  * Installation
  * Building and customizing your site
  * Multisite configuration
- * Multilingual configuration
  * More information
 
 REQUIREMENTS AND NOTES
@@ -83,7 +82,27 @@ INSTALLATION
 
      mv drupal-x.y/* drupal-x.y/.htaccess /path/to/your/installation
 
-2. Create the Drupal database.
+2. Optionally, download a translation.
+
+   By default, Drupal is installed in English, and further languages may be
+   installed later. If you prefer to install Drupal in another language
+   initially:
+
+   - Download a translation file for the correct Drupal version and language
+     from the translation server: http://localize.drupal.org/translate/downloads
+
+   - Place the file into the dedicated translations directory. By default this
+     directory is:
+
+       sites/default/files/translations/
+
+     If the directory doesn't exist, you should create it. Make sure your file
+     is named drupal-VERSION.LANGCODE.po (for example, the German
+     translation for Drupal 8.0 should be named drupal-8.0.de.po).
+
+   For detailed instructions, visit http://drupal.org/localize
+
+3. Create the Drupal database.
 
    Because Drupal stores all site information in a database, the Drupal
    installer will attempt to create this database for you. If you create the
@@ -95,7 +114,7 @@ INSTALLATION
    Take note of the username, password, database name, and hostname as you
    create the database. You will enter this information during the install.
 
-3. Run the install script.
+4. Run the install script.
 
    To run the install script, point your browser to the base URL of your
    website (e.g., http://www.example.com).
@@ -175,7 +194,7 @@ INSTALLATION
         chmod go-w sites/default/settings.php
         chmod go-w sites/default
 
-4. Verify that the site is working.
+5. Verify that the site is working.
 
    When the install script finishes, you will be logged in with the site
    maintenance account on a "Welcome" page. If the default Drupal theme is not
@@ -183,7 +202,7 @@ INSTALLATION
    you may be experiencing problems with clean URLs. Visit
    http://drupal.org/getting-started/clean-urls to troubleshoot.
 
-5. Change file system storage settings (optional).
+6. Change file system storage settings (optional).
 
    The files directory created in step 4 is the default file system path used to
    store all uploaded files, as well as some temporary files created by
@@ -223,7 +242,7 @@ INSTALLATION
    on an existing site, remember to copy all files from the original location
    to the new location.
 
-6. Revoke documentation file permissions (optional).
+7. Revoke documentation file permissions (optional).
 
    Some administrators suggest making the documentation files, especially
    CHANGELOG.txt, non-readable so that the exact version of Drupal you are
@@ -243,7 +262,7 @@ INSTALLATION
    "Modifying Windows file permissions" (http://drupal.org/node/202491) in the
    Drupal.org online documentation.
 
-7. Set up independent "cron" maintenance jobs.
+8. Set up independent "cron" maintenance jobs.
 
    Many Drupal modules have tasks that must be run periodically, including the
    Search module (building and updating the index used for keyword searching),
@@ -365,14 +384,6 @@ settings, consult http://drupal.org/getting-started/6/install/multi-site
 For more information on configuring Drupal's file system path in a multisite
 configuration, see step 6 above.
 
-MULTILINGUAL CONFIGURATION
---------------------------
-
-By default, Drupal is installed in one language, and further languages may be
-installed later.
-
-For detailed instructions, visit http://drupal.org/documentation/multilingual
-
 MORE INFORMATION
 ----------------
 
diff --git a/core/core.services.yml b/core/core.services.yml
index 43c6d24..f70ace6 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -253,9 +253,6 @@ services:
   entity.query.config:
     class: Drupal\Core\Config\Entity\Query\QueryFactory
     arguments: ['@config.storage']
-  entity.query.sql:
-    class: Drupal\Core\Entity\Query\Sql\QueryFactory
-    arguments: ['@database']
   router.dumper:
     class: Drupal\Core\Routing\MatcherDumper
     arguments: ['@database']
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 8081782..1ecd819 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -2096,7 +2096,7 @@ function install_check_translations($install_state) {
   else {
     $requirements['translations directory exists'] = array(
       'title'       => t('Translations directory'),
-      'value'       => t('The directory %translations_directory exists.', array('%translations_directory' => $translations_directory)),
+      'value'       => t('The diretory %translations_directory exists.', array('%translations_directory' => $translations_directory)),
     );
     // If the translations directory is not readable, throw an error.
     if (!$readable) {
@@ -2529,8 +2529,8 @@ function install_configure_form_submit($form, &$form_state) {
   $account->name = $form_state['values']['account']['name'];
   $account->save();
   // Load global $user and perform final login tasks.
-  $account = user_load(1);
-  user_login_finalize($account);
+  $user = user_load(1);
+  user_login_finalize();
 
   // Record when this install ran.
   variable_set('install_time', $_SERVER['REQUEST_TIME']);
diff --git a/core/includes/theme.maintenance.inc b/core/includes/theme.maintenance.inc
index 34ca45a..0077f88 100644
--- a/core/includes/theme.maintenance.inc
+++ b/core/includes/theme.maintenance.inc
@@ -92,8 +92,8 @@ function _drupal_maintenance_theme() {
   }
   _drupal_theme_initialize($themes[$theme], array_reverse($base_theme), '_theme_load_offline_registry');
 
-  // These CSS files are normally added by system_page_build() -except maintenance.css.
-  // When the database is inactive it's not called so we add them here.
+  // These are usually added from system_init() -except maintenance.css.
+  // When the database is inactive it's not called so we add it here.
   $path = drupal_get_path('module', 'system');
   drupal_add_css($path . '/css/system.module.css');
   drupal_add_css($path . '/css/system.theme.css');
diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php
index 41c3ba6..f0d1c5c 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityListController.php
@@ -25,18 +25,15 @@ public function load() {
   }
 
   /**
-   * {@inheritdoc}
+   * Overrides \Drupal\Core\Entity\EntityListController::getOperations();
    */
   public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
     $uri = $entity->uri();
 
-    // Ensure the edit operation exists since it is access controlled.
-    if (isset($operations['edit'])) {
-      // For configuration entities edit path is the MENU_DEFAULT_LOCAL_TASK and
-      // therefore should be accessed by the short route.
-      $operations['edit']['href'] = $uri['path'];
-    }
+    // For configuration entities edit path is the MENU_DEFAULT_LOCAL_TASK and
+    // therefore should be accessed by the short route.
+    $operations['edit']['href'] = $uri['path'];
 
     if (isset($this->entityInfo['entity_keys']['status'])) {
       if (!$entity->status()) {
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index b647009..c9fc572 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -556,6 +556,6 @@ public function baseFieldDefinitions() {
    * Implements \Drupal\Core\Entity\EntityStorageControllerInterface::getQueryServiceName().
    */
   public function getQueryServiceName() {
-    return 'entity.query.sql';
+    return 'entity.query.field_sql_storage';
   }
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php
index 2c9d6fd..4c436ca 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessController.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php
@@ -67,11 +67,11 @@ public function access(EntityInterface $entity, $operation, $langcode = Language
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity for which to check 'create' access.
    * @param string $operation
-   *   The entity operation. Usually one of 'view', 'update', 'create' or
+   *   The entity operation. Usually one of 'view', 'edit', 'create' or
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
-   * @param \Drupal\Core\Session\AccountInterface $account
+   * @param \Drupal\Core\Session\AccountInterface; $account
    *   The user for which to check access.
    *
    * @return bool|null
@@ -88,7 +88,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity for which to check 'create' access.
    * @param string $operation
-   *   The entity operation. Usually one of 'view', 'update', 'create' or
+   *   The entity operation. Usually one of 'view', 'edit', 'create' or
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
@@ -113,12 +113,10 @@ protected function getCache(EntityInterface $entity, $operation, $langcode, Acco
   /**
    * Statically caches whether the given user has access.
    *
-   * @param bool $access
-   *   TRUE if the user has access, FALSE otherwise.
    * @param \Drupal\Core\Entity\EntityInterface $entity
    *   The entity for which to check 'create' access.
    * @param string $operation
-   *   The entity operation. Usually one of 'view', 'update', 'create' or
+   *   The entity operation. Usually one of 'view', 'edit', 'create' or
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
diff --git a/core/lib/Drupal/Core/Entity/EntityFormController.php b/core/lib/Drupal/Core/Entity/EntityFormController.php
index d34d3f0..d7107c5 100644
--- a/core/lib/Drupal/Core/Entity/EntityFormController.php
+++ b/core/lib/Drupal/Core/Entity/EntityFormController.php
@@ -59,15 +59,7 @@ public function setOperation($operation) {
    * {@inheritdoc}
    */
   public function getBaseFormID() {
-    // Assign ENTITYTYPE_form as base form ID to invoke corresponding
-    // hook_form_alter(), #validate, #submit, and #theme callbacks, but only if
-    // it is different from the actual form ID, since callbacks would be invoked
-    // twice otherwise.
-    $base_form_id = $this->entity->entityType() . '_form';
-    if ($base_form_id == $this->getFormID()) {
-      $base_form_id = '';
-    }
-    return $base_form_id;
+    return $this->entity->entityType() . '_form';
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityListController.php b/core/lib/Drupal/Core/Entity/EntityListController.php
index 1ebab9e..b5a5f9c 100644
--- a/core/lib/Drupal/Core/Entity/EntityListController.php
+++ b/core/lib/Drupal/Core/Entity/EntityListController.php
@@ -91,29 +91,22 @@ public function load() {
   }
 
   /**
-   * {@inheritdoc}
+   * Implements \Drupal\Core\Entity\EntityListControllerInterface::getOperations().
    */
   public function getOperations(EntityInterface $entity) {
     $uri = $entity->uri();
-
-    $operations = array();
-    if ($entity->access('update')) {
-      $operations['edit'] = array(
-        'title' => t('Edit'),
-        'href' => $uri['path'] . '/edit',
-        'options' => $uri['options'],
-        'weight' => 10,
-      );
-    }
-    if ($entity->access('delete')) {
-      $operations['delete'] = array(
-        'title' => t('Delete'),
-        'href' => $uri['path'] . '/delete',
-        'options' => $uri['options'],
-        'weight' => 100,
-      );
-    }
-
+    $operations['edit'] = array(
+      'title' => t('Edit'),
+      'href' => $uri['path'] . '/edit',
+      'options' => $uri['options'],
+      'weight' => 10,
+    );
+    $operations['delete'] = array(
+      'title' => t('Delete'),
+      'href' => $uri['path'] . '/delete',
+      'options' => $uri['options'],
+      'weight' => 100,
+    );
     return $operations;
   }
 
@@ -189,9 +182,7 @@ public function render() {
       '#empty' => t('There is no @label yet.', array('@label' => $this->entityInfo['label'])),
     );
     foreach ($this->load() as $entity) {
-      if ($row = $this->buildRow($entity)) {
-        $build['#rows'][$entity->id()] = $row;
-      }
+      $build['#rows'][$entity->id()] = $this->buildRow($entity);
     }
     return $build;
   }
diff --git a/core/lib/Drupal/Core/Entity/EntityNG.php b/core/lib/Drupal/Core/Entity/EntityNG.php
index a45c55a..899ae9f 100644
--- a/core/lib/Drupal/Core/Entity/EntityNG.php
+++ b/core/lib/Drupal/Core/Entity/EntityNG.php
@@ -235,13 +235,6 @@ protected function getTranslatedField($property_name, $langcode) {
         if (isset($this->values[$property_name][$langcode])) {
           $value = $this->values[$property_name][$langcode];
         }
-        // @todo Remove this once the BC decorator is gone.
-        elseif ($property_name != 'langcode') {
-          $default_langcode = $this->language()->langcode;
-          if ($langcode == Language::LANGCODE_DEFAULT && isset($this->values[$property_name][$default_langcode])) {
-            $value = $this->values[$property_name][$default_langcode];
-          }
-        }
         $this->fields[$property_name][$langcode] = \Drupal::typedData()->getPropertyInstance($this, $property_name, $value);
       }
     }
diff --git a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
index 46a66b9..d21c8cc 100644
--- a/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
+++ b/core/lib/Drupal/Core/Entity/Field/FieldItemBase.php
@@ -177,4 +177,9 @@ public function delete() { }
    */
   public function deleteRevision() { }
 
+  /**
+   * {@inheritdoc}
+   */
+  public static function prepareView(array $entities_items) { }
+
 }
diff --git a/core/modules/action/lib/Drupal/action/ActionAccessController.php b/core/modules/action/lib/Drupal/action/ActionAccessController.php
deleted file mode 100644
index 90a8e5c..0000000
--- a/core/modules/action/lib/Drupal/action/ActionAccessController.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\action\ActionAccessController.
- */
-
-namespace Drupal\action;
-
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Language\Language;
-use Drupal\Core\Session\AccountInterface;
-
-class ActionAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(EntityInterface $entity, $operation, $langcode = Language::LANGUAGE_DEFAULT, AccountInterface $account = NULL) {
-    return user_access('administer actions', $account);
-  }
-
-}
diff --git a/core/modules/action/lib/Drupal/action/ActionListController.php b/core/modules/action/lib/Drupal/action/ActionListController.php
index f3d5848..1ad8319 100644
--- a/core/modules/action/lib/Drupal/action/ActionListController.php
+++ b/core/modules/action/lib/Drupal/action/ActionListController.php
@@ -109,8 +109,9 @@ public function buildHeader() {
    * {@inheritdoc}
    */
   public function getOperations(EntityInterface $entity) {
-    $operations = $entity->isConfigurable() ? parent::getOperations($entity) : array();
-    if (isset($operations['edit'])) {
+    $operations = array();
+    if ($entity->isConfigurable()) {
+      $operations = parent::getOperations($entity);
       $operations['edit']['title'] = t('Configure');
     }
     return $operations;
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeAccessController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeAccessController.php
deleted file mode 100644
index 3aa95ce..0000000
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeAccessController.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\custom_block\CustomBlockTypeAccessController.
- */
-
-namespace Drupal\custom_block;
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines the access controller for the custom block type entity type.
- */
-class CustomBlockTypeAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
-    if ($operation === 'view') {
-      return TRUE;
-    }
-    elseif (in_array($operation, array('create', 'update', 'delete'))) {
-      return user_access('administer blocks', $account);
-    }
-  }
-
-}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
index eab2bcd..8ef270c 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
@@ -16,7 +16,7 @@
 class CustomBlockTypeListController extends ConfigEntityListController {
 
   /**
-   * {@inheritdoc}
+   * Overrides \Drupal\Core\Entity\EntityListController::getOperations().
    */
   public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php
index 0ceabd5..4d5f33b 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php
@@ -22,7 +22,6 @@
  *   module = "custom_block",
  *   controllers = {
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
- *     "access" = "Drupal\custom_block\CustomBlockTypeAccessController",
  *     "form" = {
  *       "default" = "Drupal\custom_block\CustomBlockTypeFormController",
  *       "delete" = "Drupal\custom_block\Form\CustomBlockTypeDeleteForm"
diff --git a/core/modules/book/book.install b/core/modules/book/book.install
index 610808b..7d70a02 100644
--- a/core/modules/book/book.install
+++ b/core/modules/book/book.install
@@ -6,6 +6,14 @@
  */
 
 /**
+ * Implements hook_install().
+ */
+function book_install() {
+  // Add the node type.
+  _book_install_type_create();
+}
+
+/**
  * Implements hook_uninstall().
  */
 function book_uninstall() {
@@ -17,6 +25,28 @@ function book_uninstall() {
 }
 
 /**
+ * Creates the book content type.
+ */
+function _book_install_type_create() {
+  // Create an additional node type.
+  $book_node_type = array(
+    'type' => 'book',
+    'name' => t('Book page'),
+    'base' => 'node_content',
+    'description' => t('<em>Books</em> have a built-in hierarchical navigation. Use for handbooks or tutorials.'),
+    'custom' => 1,
+    'modified' => 1,
+    'locked' => 0,
+  );
+
+  $book_node_type = node_type_set_defaults($book_node_type);
+  node_type_save($book_node_type);
+  node_add_body_field($book_node_type);
+  // Default to not promoted.
+  variable_set('node_options_book', array('status'));
+}
+
+/**
  * Implements hook_schema().
  */
 function book_schema() {
diff --git a/core/modules/book/book.module b/core/modules/book/book.module
index 3462abf..1fe04c8 100644
--- a/core/modules/book/book.module
+++ b/core/modules/book/book.module
@@ -6,7 +6,6 @@
  */
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Language\Language;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\Core\Template\Attribute;
@@ -1231,24 +1230,25 @@ function book_type_is_allowed($type) {
  * Updates book.settings configuration object if the machine-readable name of a
  * node type is changed.
  */
-function book_node_type_update(NodeTypeInterface $type) {
-  if ($type->getOriginalID() != $type->id()) {
+function book_node_type_update($type) {
+  if (!empty($type->old_type) && $type->old_type != $type->type) {
     $config = config('book.settings');
     // Update the list of node types that are allowed to be added to books.
     $allowed_types = $config->get('allowed_types');
-    $old_key = array_search($type->getOriginalID(), $allowed_types);
-
+    $old_key = array_search($type->old_type, $allowed_types);
     if ($old_key !== FALSE) {
-      $allowed_types[$old_key] = $type->id();
+      // Replace the old machine-readable name with the new machine-readable
+      // name.
+      $allowed_types[$old_key] = $type->type;
       // Ensure that the allowed_types array is sorted consistently.
-      // @see BookSettingsForm::submitForm()
+      // @see book_admin_settings_submit()
       sort($allowed_types);
       $config->set('allowed_types', $allowed_types);
     }
 
     // Update the setting for the "Add child page" link.
-    if ($config->get('child_type') == $type->getOriginalID()) {
-      $config->set('child_type', $type->id());
+    if ($config->get('child_type') == $type->old_type) {
+      $config->set('child_type', $type->type);
     }
     $config->save();
   }
diff --git a/core/modules/book/config/node.type.book.yml b/core/modules/book/config/node.type.book.yml
deleted file mode 100644
index 2b39fd1..0000000
--- a/core/modules/book/config/node.type.book.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-type: book
-uuid: c5ca890d-7db7-4c45-bf0f-0a12430923ff
-name: 'Book page'
-description: '<em>Books</em> have a built-in hierarchical navigation. Use for handbooks or tutorials.'
-help: ''
-has_title: '1'
-title_label: Title
-settings:
-  node:
-    preview: '1'
-    options:
-      status: status
-      # Not promoted to front page.
-      promote: '0'
-      sticky: '0'
-      revision: '0'
-    submitted: '1'
-status: '1'
-langcode: en
diff --git a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
index 9f40120..5ab4961 100644
--- a/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
+++ b/core/modules/ckeditor/lib/Drupal/ckeditor/Plugin/Editor/CKEditor.php
@@ -116,10 +116,6 @@ public function settingsForm(array $form, array &$form_state, EditorEntity $edit
         'plugins' => $editor->settings['plugins'],
       ),
     ));
-    $config = $this->getJSSettings($fake_editor);
-    // Remove the ACF configuration that is generated based on filter settings,
-    // because otherwise we cannot retrieve per-feature metadata.
-    unset($config['allowedContent']);
     $form['hidden_ckeditor'] = array(
       '#markup' => '<div id="ckeditor-hidden" class="element-hidden"></div>',
       '#attached' => array(
@@ -127,7 +123,7 @@ public function settingsForm(array $form, array &$form_state, EditorEntity $edit
           array(
             'type' => 'setting',
             'data' => array('ckeditor' => array(
-              'hiddenCKEditorConfig' => $config,
+              'hiddenCKEditorConfig' => $this->getJSSettings($fake_editor),
             )),
           ),
         ),
diff --git a/core/modules/comment/comment.install b/core/modules/comment/comment.install
index efaf9f3..71b2cf0 100644
--- a/core/modules/comment/comment.install
+++ b/core/modules/comment/comment.install
@@ -69,6 +69,9 @@ function comment_modules_enabled($modules) {
   // hook_node_type_insert() is used to create body fields while the comment
   // module is enabled.
   if (in_array('comment', $modules)) {
+    // Ensure that the list of node types reflects newly enabled modules.
+    node_types_rebuild();
+
     // Create comment body fields for each node type, if needed.
     foreach (node_type_get_types() as $type => $info) {
       _comment_body_field_create($info);
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 7cd4e70..2466ce7 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -9,7 +9,6 @@
  * book page, etc.
  */
 
-use Drupal\node\NodeTypeInterface;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\file\Plugin\Core\Entity\File;
 use Drupal\Core\Entity\EntityInterface;
@@ -115,6 +114,25 @@ function comment_entity_bundle_info() {
 }
 
 /**
+ * Loads the comment bundle name corresponding a given content type.
+ *
+ * This function is used as a menu loader callback in comment_menu().
+ *
+ * @param $name
+ *   The machine name of the node type whose comment fields are to be edited.
+ *
+ * @return
+ *   The comment bundle name corresponding to the node type.
+ *
+ * @see comment_menu_alter()
+ */
+function comment_node_type_load($name) {
+  if ($type = node_type_load($name)) {
+    return 'comment_node_' . $type->type;
+  }
+}
+
+/**
  * Entity URI callback.
  */
 function comment_uri(Comment $comment) {
@@ -259,10 +277,10 @@ function comment_menu_alter(&$items) {
 
   // Adjust the Field UI tabs on admin/structure/types/manage/[node-type].
   // See comment_entity_bundle_info().
-  $items['admin/structure/types/manage/{bundle}/comment/fields']['title'] = 'Comment fields';
-  $items['admin/structure/types/manage/{bundle}/comment/fields']['weight'] = 3;
-  $items['admin/structure/types/manage/{bundle}/comment/display']['title'] = 'Comment display';
-  $items['admin/structure/types/manage/{bundle}/comment/display']['weight'] = 4;
+  $items['admin/structure/types/manage/%/comment/fields']['title'] = 'Comment fields';
+  $items['admin/structure/types/manage/%/comment/fields']['weight'] = 3;
+  $items['admin/structure/types/manage/%/comment/display']['title'] = 'Comment display';
+  $items['admin/structure/types/manage/%/comment/display']['weight'] = 4;
 }
 
 /**
@@ -291,9 +309,9 @@ function comment_node_type_insert($info) {
 /**
  * Implements hook_node_type_update().
  */
-function comment_node_type_update(NodeTypeInterface $type) {
-  if ($type->original->id() != $type->id()) {
-    entity_invoke_bundle_hook('rename', 'comment', 'comment_node_' . $type->original->id(), 'comment_node_' . $type->id());
+function comment_node_type_update($info) {
+  if (!empty($info->old_type) && $info->type != $info->old_type) {
+    entity_invoke_bundle_hook('rename', 'comment', 'comment_node_' . $info->old_type, 'comment_node_' . $info->type);
   }
 }
 
@@ -972,7 +990,6 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL)
  */
 function comment_form_node_type_form_alter(&$form, $form_state) {
   if (isset($form['type'])) {
-    $node_type = $form_state['controller']->getEntity();
     $form['comment'] = array(
       '#type' => 'details',
       '#title' => t('Comment settings'),
@@ -991,7 +1008,7 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     $form['comment']['comment'] = array(
       '#type' => 'select',
       '#title' => t('Default comment setting for new content'),
-      '#default_value' => variable_get('comment_' . $node_type->id(), COMMENT_NODE_OPEN),
+      '#default_value' => variable_get('comment_' . $form['#node_type']->type, COMMENT_NODE_OPEN),
       '#options' => array(
         COMMENT_NODE_OPEN => t('Open'),
         COMMENT_NODE_CLOSED => t('Closed'),
@@ -1001,19 +1018,19 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     $form['comment']['comment_default_mode'] = array(
       '#type' => 'checkbox',
       '#title' => t('Threading'),
-      '#default_value' => variable_get('comment_default_mode_' . $node_type->id(), COMMENT_MODE_THREADED),
+      '#default_value' => variable_get('comment_default_mode_' . $form['#node_type']->type, COMMENT_MODE_THREADED),
       '#description' => t('Show comment replies in a threaded list.'),
     );
     $form['comment']['comment_default_per_page'] = array(
       '#type' => 'select',
       '#title' => t('Comments per page'),
-      '#default_value' => variable_get('comment_default_per_page_' . $node_type->id(), 50),
+      '#default_value' => variable_get('comment_default_per_page_' . $form['#node_type']->type, 50),
       '#options' => _comment_per_page(),
     );
     $form['comment']['comment_anonymous'] = array(
       '#type' => 'select',
       '#title' => t('Anonymous commenting'),
-      '#default_value' => variable_get('comment_anonymous_' . $node_type->id(), COMMENT_ANONYMOUS_MAYNOT_CONTACT),
+      '#default_value' => variable_get('comment_anonymous_' . $form['#node_type']->type, COMMENT_ANONYMOUS_MAYNOT_CONTACT),
       '#options' => array(
         COMMENT_ANONYMOUS_MAYNOT_CONTACT => t('Anonymous posters may not enter their contact information'),
         COMMENT_ANONYMOUS_MAY_CONTACT => t('Anonymous posters may leave their contact information'),
@@ -1024,17 +1041,17 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     $form['comment']['comment_subject_field'] = array(
       '#type' => 'checkbox',
       '#title' => t('Allow comment title'),
-      '#default_value' => variable_get('comment_subject_field_' . $node_type->id(), 1),
+      '#default_value' => variable_get('comment_subject_field_' . $form['#node_type']->type, 1),
     );
     $form['comment']['comment_form_location'] = array(
       '#type' => 'checkbox',
       '#title' => t('Show reply form on the same page as comments'),
-      '#default_value' => variable_get('comment_form_location_' . $node_type->id(), COMMENT_FORM_BELOW),
+      '#default_value' => variable_get('comment_form_location_' . $form['#node_type']->type, COMMENT_FORM_BELOW),
     );
     $form['comment']['comment_preview'] = array(
       '#type' => 'radios',
       '#title' => t('Preview comment'),
-      '#default_value' => variable_get('comment_preview_' . $node_type->id(), DRUPAL_OPTIONAL),
+      '#default_value' => variable_get('comment_preview_' . $form['#node_type']->type, DRUPAL_OPTIONAL),
       '#options' => array(
         DRUPAL_DISABLED => t('Disabled'),
         DRUPAL_OPTIONAL => t('Optional'),
@@ -1045,7 +1062,7 @@ function comment_form_node_type_form_alter(&$form, $form_state) {
     if (module_exists('content_translation')) {
       $comment_form = $form;
       $comment_form_state['content_translation']['key'] = 'language_configuration';
-      $form['comment'] += translation_entity_enable_widget('comment', 'comment_node_' . $node_type->id(), $comment_form, $comment_form_state);
+      $form['comment'] += content_translation_enable_widget('comment', 'comment_node_' . $form['#node_type']->type, $comment_form, $comment_form_state);
       array_unshift($form['#submit'], 'comment_translation_configuration_element_submit');
     }
   }
@@ -1067,7 +1084,7 @@ function comment_translation_configuration_element_submit($form, &$form_state) {
   $key = 'language_configuration';
   $comment_form_state = array(
     'content_translation' => array('key' => $key),
-    'language' => array($key => array('entity_type' => 'comment', 'bundle' => 'comment_node_' . $form_state['controller']->getEntity()->id())),
+    'language' => array($key => array('entity_type' => 'comment', 'bundle' => 'comment_node_' . $form['#node_type']->type)),
     'values' => array($key => array('content_translation' => $form_state['values']['content_translation'])),
   );
   content_translation_language_configuration_element_submit($form, $comment_form_state);
diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestAccessController.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestAccessController.php
deleted file mode 100644
index c973c5a..0000000
--- a/core/modules/config/tests/config_test/lib/Drupal/config_test/ConfigTestAccessController.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\config_test\ConfigTestAccessController.
- */
-
-namespace Drupal\config_test;
-
-use Drupal\Core\Session\AccountInterface;
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Language\Language;
-
-/**
- * Defines the access controller for the config_test entity type.
- */
-class ConfigTestAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(EntityInterface $entity, $operation, $langcode = Language::LANGUAGE_DEFAULT, AccountInterface $account = NULL) {
-    return TRUE;
-  }
-
-}
diff --git a/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php b/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php
index dc76288..12a033b 100644
--- a/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php
+++ b/core/modules/config/tests/config_test/lib/Drupal/config_test/Plugin/Core/Entity/ConfigTest.php
@@ -25,8 +25,7 @@
  *     "form" = {
  *       "default" = "Drupal\config_test\ConfigTestFormController",
  *       "delete" = "Drupal\config_test\Form\ConfigTestDeleteForm"
- *     },
- *     "access" = "Drupal\config_test\ConfigTestAccessController"
+ *     }
  *   },
  *   uri_callback = "config_test_uri",
  *   config_prefix = "config_test.dynamic",
diff --git a/core/modules/contact/lib/Drupal/contact/CategoryListController.php b/core/modules/contact/lib/Drupal/contact/CategoryListController.php
index db3f829..25f18f2 100644
--- a/core/modules/contact/lib/Drupal/contact/CategoryListController.php
+++ b/core/modules/contact/lib/Drupal/contact/CategoryListController.php
@@ -34,6 +34,13 @@ public function getOperations(EntityInterface $entity) {
         'weight' => 12,
       );
     }
+
+    if (!$entity->access('delete')) {
+      unset($operations['delete']);
+    }
+    if (!$entity->access('update')) {
+      unset($operations['edit']);
+    }
     return $operations;
   }
 
diff --git a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php
index 568ee74..7bfa73f 100644
--- a/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php
+++ b/core/modules/content_translation/lib/Drupal/content_translation/Tests/ContentTranslationSyncImageTest.php
@@ -119,7 +119,7 @@ function testImageFieldSync() {
       // Generate the item for the current image file entity and attach it to
       // the entity.
       $item = array(
-        'target_id' => $fid,
+        'fid' => $fid,
         'alt' => $default_langcode . '_' . $fid . '_' . $this->randomName(),
         'title' => $default_langcode . '_' . $fid . '_' . $this->randomName(),
       );
@@ -144,7 +144,7 @@ function testImageFieldSync() {
       // the entity.
       $fid = $this->files[$index]->fid;
       $item = array(
-        'target_id' => $fid,
+        'fid' => $fid,
         'alt' => $langcode . '_' . $fid . '_' . $this->randomName(),
         'title' => $langcode . '_' . $fid . '_' . $this->randomName(),
       );
@@ -166,11 +166,11 @@ function testImageFieldSync() {
     // have been retained.
     $fids = array();
     foreach ($entity->{$this->fieldName} as $delta => $item) {
-      $value = $values[$default_langcode][$item->target_id];
+      $value = $values[$default_langcode][$item->fid];
       $source_item = $entity->getTranslation($langcode)->{$this->fieldName}->offsetGet($delta);
-      $assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
-      $this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item->target_id)));
-      $fids[$item->target_id] = TRUE;
+      $assert = $item->fid == $source_item->fid && $item->alt == $value['alt'] && $item->title == $value['title'];
+      $this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item->fid)));
+      $fids[$item->fid] = TRUE;
     }
 
     // Check that the dropped value is the right one.
@@ -179,7 +179,7 @@ function testImageFieldSync() {
 
     // Add back an item for the dropped value and perform synchronization again.
     $values[$langcode][$removed_fid] = array(
-      'target_id' => $removed_fid,
+      'fid' => $removed_fid,
       'alt' => $langcode . '_' . $removed_fid . '_' . $this->randomName(),
       'title' => $langcode . '_' . $removed_fid . '_' . $this->randomName(),
     );
@@ -196,11 +196,11 @@ function testImageFieldSync() {
       // When adding an item its value is copied over all the target languages,
       // thus in this case the source language needs to be used to check the
       // values instead of the target one.
-      $fid_langcode = $item->target_id != $removed_fid ? $default_langcode : $langcode;
-      $value = $values[$fid_langcode][$item->target_id];
+      $fid_langcode = $item->fid != $removed_fid ? $default_langcode : $langcode;
+      $value = $values[$fid_langcode][$item->fid];
       $source_item = $entity->getTranslation($langcode)->{$this->fieldName}->offsetGet($delta);
-      $assert = $item->target_id == $source_item->target_id && $item->alt == $value['alt'] && $item->title == $value['title'];
-      $this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item->target_id)));
+      $assert = $item->fid == $source_item->fid && $item->alt == $value['alt'] && $item->title == $value['title'];
+      $this->assertTrue($assert, format_string('Field item @fid has been successfully synchronized.', array('@fid' => $item->fid)));
     }
   }
 
diff --git a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
index a29e967..24cb092 100644
--- a/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
+++ b/core/modules/entity/lib/Drupal/entity/Tests/EntityDisplayTest.php
@@ -202,19 +202,19 @@ public function testFieldComponent() {
    * Tests renaming and deleting a bundle.
    */
   public function testRenameDeleteBundle() {
-    $this->enableModules(array('field_sql_storage', 'field_test', 'node', 'system', 'text'));
+    $this->enableModules(array('field_sql_storage', 'field_test', 'node', 'system'));
+    $this->installSchema('node', array('node_type'));
     $this->installSchema('system', array('variable'));
-    $this->installSchema('node', array('node'));
 
     // Create a node bundle and display object.
-    entity_create('node_type', array('type' => 'article'))->save();
+    node_type_save((object) array('type' => 'article'));
     entity_get_display('node', 'article', 'default')->save();
 
     // Rename the article bundle and assert the entity display is renamed.
     $info = node_type_load('article');
     $info->old_type = 'article';
     $info->type = 'article_rename';
-    $info->save();
+    node_type_save($info);
     $old_display = entity_load('entity_display', 'node.article.default');
     $this->assertFalse($old_display);
     $new_display = entity_load('entity_display', 'node.article_rename.default');
@@ -222,7 +222,7 @@ public function testRenameDeleteBundle() {
     $this->assertEqual('node.article_rename.default', $new_display->id);
 
     // Delete the bundle.
-    $info->delete();
+    node_type_delete('article_rename');
     $display = entity_load('entity_display', 'node.article_rename.default');
     $this->assertFalse($display);
   }
diff --git a/core/modules/field/field.api.php b/core/modules/field/field.api.php
index 1f4b220..20e9301 100644
--- a/core/modules/field/field.api.php
+++ b/core/modules/field/field.api.php
@@ -320,8 +320,6 @@ function hook_field_formatter_info_alter(array &$info) {
  * @param $langcode
  *   The language the field values are going to be entered in. If no language is
  *   provided the default site language will be used.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function hook_field_attach_form(\Drupal\Core\Entity\EntityInterface $entity, &$form, &$form_state, $langcode) {
   // Add a checkbox allowing a given field to be emptied.
@@ -347,8 +345,6 @@ function hook_field_attach_form(\Drupal\Core\Entity\EntityInterface $entity, &$f
  * for subsequent loads.
  *
  * See field_attach_load() for details and arguments.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function hook_field_attach_load($entity_type, $entities, $age, $options) {
   // @todo Needs function body.
@@ -369,8 +365,6 @@ function hook_field_attach_load($entity_type, $entities, $age, $options) {
  *   $form_state['values'].
  * @param $form_state
  *   An associative array containing the current state of the form.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function hook_field_attach_extract_form_values(\Drupal\Core\Entity\EntityInterface $entity, $form, &$form_state) {
   // Sample case of an 'Empty the field' checkbox added on the form, allowing
@@ -443,8 +437,6 @@ function hook_field_attach_purge(\Drupal\Core\Entity\EntityInterface $entity, $f
  *     See field_view_field() for more information on what its $display_options
  *     argument contains.
  *   - langcode: The language code used for rendering.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function hook_field_attach_view_alter(&$output, $context) {
   // Append RDF term mappings on displayed taxonomy links.
diff --git a/core/modules/field/field.attach.inc b/core/modules/field/field.attach.inc
index 8ac39d7..f9c585e 100644
--- a/core/modules/field/field.attach.inc
+++ b/core/modules/field/field.attach.inc
@@ -507,8 +507,6 @@ function _field_invoke_widget_target($form_display) {
  *   An associative array of additional options. See field_invoke_method() for
  *   details.
  *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
- *
  * @see field_form_get_state()
  * @see field_form_set_state()
  */
@@ -564,8 +562,6 @@ function field_attach_form(EntityInterface $entity, &$form, &$form_state, $langc
  *   - instance: A field instance entity, If provided, only values for the
  *     corresponding field will be loaded, and no cache is written. This
  *     option is only supported when all $entities are within the same bundle.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $options = array()) {
   $load_current = $age == FIELD_LOAD_CURRENT;
@@ -737,8 +733,6 @@ function field_attach_load($entity_type, $entities, $age = FIELD_LOAD_CURRENT, $
  * @param $options
  *   An associative array of additional options. See field_attach_load() for
  *   details.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_load_revision($entity_type, $entities, $options = array()) {
   return field_attach_load($entity_type, $entities, FIELD_LOAD_REVISION, $options);
@@ -772,8 +766,6 @@ function field_attach_load_revision($entity_type, $entities, $options = array())
  * @param array $options
  *   An associative array of additional options. See field_invoke_method() for
  *   details.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_form_validate(EntityInterface $entity, $form, &$form_state, array $options = array()) {
   // Only support NG entities.
@@ -821,8 +813,6 @@ function field_attach_form_validate(EntityInterface $entity, $form, &$form_state
  * @param array $options
  *   An associative array of additional options. See field_invoke_method() for
  *   details.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_extract_form_values(EntityInterface $entity, $form, &$form_state, array $options = array()) {
   // Ensure we are working with a BC mode entity.
@@ -853,8 +843,6 @@ function field_attach_extract_form_values(EntityInterface $entity, $form, &$form
  * @return
  *   Default values (if any) will be added to the $entity parameter for fields
  *   it leaves unspecified.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_insert(EntityInterface $entity) {
   // Ensure we are working with a BC mode entity.
@@ -894,8 +882,6 @@ function field_attach_insert(EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity with fields to save.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_update(EntityInterface $entity) {
   // Ensure we are working with a BC mode entity.
@@ -914,9 +900,16 @@ function field_attach_update(EntityInterface $entity) {
   foreach (field_info_instances($entity->entityType(), $entity->bundle()) as $instance) {
     $field = field_info_field_by_id($instance['field_id']);
     $field_id = $field['uuid'];
-    // Collect the storage backend if the field has not been written yet.
-    if (!isset($skip_fields[$field_id])) {
-      $storages[$field['storage']['type']][$field_id] = $field_id;
+    $field_name = $field['field_name'];
+    // Leave the field untouched if $entity comes with no $field_name property,
+    // but empty the field if it comes as a NULL value or an empty array.
+    // Function property_exists() is slower, so we catch the more frequent
+    // cases where it's an empty array with the faster isset().
+    if (isset($entity->$field_name) || property_exists($entity, $field_name)) {
+      // Collect the storage backend if the field has not been written yet.
+      if (!isset($skip_fields[$field_id])) {
+        $storages[$field['storage']['type']][$field_id] = $field_id;
+      }
     }
   }
 
@@ -938,8 +931,6 @@ function field_attach_update(EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity whose field data to delete.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_delete(EntityInterface $entity) {
   // Ensure we are working with a BC mode entity.
@@ -971,8 +962,6 @@ function field_attach_delete(EntityInterface $entity) {
  *
  * @param \Drupal\Core\Entity\EntityInterface $entity
  *   The entity with fields to save.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_delete_revision(EntityInterface $entity) {
   // Ensure we are working with a BC mode entity.
@@ -1016,8 +1005,6 @@ function field_attach_delete_revision(EntityInterface $entity) {
  * @param $langcode
  *   (Optional) The language the field values are to be shown in. If no language
  *   is provided the current language is used.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_prepare_view($entity_type, array $entities, array $displays, $langcode = NULL) {
   $options['langcode'] = array();
@@ -1080,8 +1067,6 @@ function field_attach_prepare_view($entity_type, array $entities, array $display
  *
  * @return array
  *   A renderable array for the field values.
- *
- * @deprecated as of Drupal 8.0. Use the entity system instead.
  */
 function field_attach_view(EntityInterface $entity, EntityDisplay $display, $langcode = NULL, array $options = array()) {
   // Ensure we are working with a BC mode entity.
@@ -1176,7 +1161,7 @@ function field_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
     }
   }
 
-  // Clear the field cache.
+  // Clear the cache.
   field_cache_clear();
 
   // Update bundle settings.
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index 1694e2e..d73991c 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -657,9 +657,6 @@ function _field_filter_xss_display_allowed_tags() {
 function field_view_value(EntityInterface $entity, $field_name, $item, $display = array(), $langcode = NULL) {
   $output = array();
 
-  // Ensure we are working with a BC mode entity.
-  $entity = $entity->getBCEntity();
-
   if ($field = field_info_field($field_name)) {
     // Determine the langcode that will be used by language fallback.
     $langcode = field_language($entity, $field_name, $langcode);
@@ -776,11 +773,21 @@ function field_view_field(EntityInterface $entity, $field_name, $display_options
       $items = \Drupal::typedData()->create($definitions[$field_name], $itemsBC, $field_name, $entity);
     }
 
-    // Invoke the formatter's prepareView() and view() methods.
+    // Invoke prepare_view steps if needed.
     $id = $entity->id();
+
+    // First let the field type do its preparation. prepareView() is a static
+    // method.
+    $type_definition = \Drupal::typedData()->getDefinition($definition['type']);
+    $class = $type_definition['class'];
+    $class::prepareView(array($id => $items), $definition);
+
+    // Then let the formatter do its own specific massaging.
     $itemsBC_multi = array($id => $items->getValue());
     $formatter->prepareView(array($id => $entity), $display_langcode, $itemsBC_multi);
     $itemsBC = $itemsBC_multi[$id];
+
+    // Build the renderable array.
     $result = $formatter->view($entity, $display_langcode, $itemsBC);
 
     // Invoke hook_field_attach_view_alter() to let other modules alter the
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
index 7406134..4535159 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/FieldType/ConfigEntityReferenceItemBase.php
@@ -93,7 +93,7 @@ public function getPropertyDefinitions() {
    * since we cannot extend it.
    */
   public static function schema(Field $field) {
-    $definition = \Drupal::service('plugin.manager.entity.field.field_type')->getDefinition($field->type);
+    $definition = \Drupal::typedData()->getDefinition('field_item:' . $field->type);
     $module = $definition['module'];
     module_load_install($module);
     $callback = "{$module}_field_schema";
diff --git a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterInterface.php b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterInterface.php
index dda43b0..8f7f3df 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterInterface.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/Type/Formatter/FormatterInterface.php
@@ -53,6 +53,9 @@ public function settingsSummary();
    * field that displays properties of the referenced entities such as name or
    * type.
    *
+   * This method is called after the field type's implementation of
+   * hook_field_prepare_view().
+   *
    * This method operates on multiple entities. The $entities and $items
    * parameters are arrays keyed by entity ID. For performance reasons,
    * information for all involved entities should be loaded in a single query
diff --git a/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php b/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php
index 0f122b6..d965401 100644
--- a/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php
+++ b/core/modules/field/lib/Drupal/field/Plugin/field/field_type/LegacyConfigFieldItem.php
@@ -107,6 +107,50 @@ public function prepareCache() {
   }
 
   /**
+   * {@inherotdoc}
+   */
+  public static function prepareView(array $entities_items) {
+    if ($entities_items) {
+      // Determine the legacy callback.
+      $field_type_definition = current($entities_items)->getPluginDefinition();
+      $module = $field_type_definition['module'];
+      $callback = "{$module}_field_prepare_view";
+      if (function_exists($callback)) {
+        $entities = array();
+        $instances = array();
+        $itemsBC = array();
+        foreach ($entities_items as $id => $items) {
+          $entities[$id] = $items->getParent();
+          $instances[$id] = $items->offsetGet(0)->getInstance();
+          // We need to remove the empty "prototype" item here.
+          // @todo Revisit after http://drupal.org/node/1988492.
+          $items->filterEmptyValues();
+          $itemsBC[$id] = $items->getValue(TRUE);
+        }
+
+        // Determine the entity type, langcode and field.
+        $entity_type = current($entities)->entityType();
+        $langcode = current($entities)->language()->langcode;
+        $field = current($instances)->getField();
+
+        $args = array(
+          $entity_type,
+          $entities,
+          $field,
+          $instances,
+          $langcode,
+          &$itemsBC,
+        );
+        call_user_func_array($callback, $args);
+
+        foreach ($entities_items as $id => $items) {
+          $items->setValue($itemsBC[$id]);
+        }
+      }
+    }
+  }
+
+  /**
    * Returns the legacy callback for a given field type "hook".
    *
    * @param string $hook
diff --git a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
index 9637826..16ec6f2 100644
--- a/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/BulkDeleteTest.php
@@ -8,7 +8,6 @@
 namespace Drupal\field\Tests;
 
 use Drupal\field\Plugin\Core\Entity\FieldInstance;
-use Drupal\Core\Entity\EntityInterface;
 
 use Drupal\Core\Language\Language;
 
@@ -61,6 +60,36 @@ public static function getInfo() {
   }
 
   /**
+   * Converts the passed entities to partially created ones.
+   *
+   * This replicates the partial entities created in field_purge_data_batch(),
+   * which only have the ids and the to be deleted field defined.
+   *
+   * @param $entities
+   *   An array of entities of type test_entity.
+   * @param $field_name
+   *   A field name whose data should be copied from $entities into the returned
+   *   partial entities.
+   * @return array An array of partial entities corresponding to $entities.
+   */
+  protected function convertToPartialEntities($entities, $field_name) {
+    $partial_entities = array();
+    foreach ($entities as $id => $entity) {
+      // Re-create the entity to match what is expected
+      // _field_create_entity_from_ids().
+      $ids = (object) array(
+        'entity_id' => $entity->ftid,
+        'revision_id' => $entity->ftvid,
+        'bundle' => $entity->fttype,
+        'entity_type' => 'test_entity',
+      );
+      $partial_entities[$id] = _field_create_entity_from_ids($ids);
+      $partial_entities[$id]->$field_name = $entity->$field_name;
+    }
+    return $partial_entities;
+  }
+
+  /**
    * Tests that the expected hooks have been invoked on the expected entities.
    *
    * @param $expected_hooks
@@ -81,15 +110,8 @@ function checkHooksInvocations($expected_hooks, $actual_hooks) {
       foreach ($invocations as $argument) {
         $found = FALSE;
         foreach ($actual_invocations as $actual_arguments) {
-          // The argument we are looking for is either an array of entities as
-          // the second argument or a single entity object as the first.
-          if ($argument instanceof EntityInterface && $actual_arguments[0]->id() == $argument->id()) {
-            $found = TRUE;
-            break;
-          }
-          // In case of an array, compare the array size and make sure it
-          // contains the same elements.
-          elseif (is_array($argument) && count($actual_arguments[1]) == count($argument) && count(array_diff_key($actual_arguments[1], $argument)) == 0) {
+          // $entity is sometimes the first and sometimes the second argument.
+          if ($actual_arguments[0] == $argument || $actual_arguments[1] == $argument) {
             $found = TRUE;
             break;
           }
@@ -109,7 +131,7 @@ function setUp() {
     // Create two bundles.
     $this->bundles = array('bb_1' => 'bb_1', 'bb_2' => 'bb_2');
     foreach ($this->bundles as $name => $desc) {
-      entity_test_create_bundle($name, $desc);
+      field_test_create_bundle($name, $desc);
     }
 
     // Create two fields.
@@ -130,7 +152,7 @@ function setUp() {
 
     // For each bundle, create an instance of each field, and 10
     // entities with values for each field.
-    $this->entity_type = 'entity_test';
+    $id = 1;
     foreach ($this->bundles as $bundle) {
       foreach ($this->fields as $field) {
         entity_create('field_instance', array(
@@ -139,18 +161,20 @@ function setUp() {
           'bundle' => $bundle,
         ))->save();
       }
+
       for ($i = 0; $i < 10; $i++) {
-        $entity = entity_create($this->entity_type, array('type' => $bundle));
+        $entity = field_test_create_entity($id, $id, $bundle);
         foreach ($this->fields as $field) {
-          $entity->{$field['field_name']}->setValue($this->_generateTestFieldValues($field->cardinality));
+          $entity->{$field->id()}[Language::LANGCODE_NOT_SPECIFIED] = $this->_generateTestFieldValues($field->cardinality);
         }
         $entity->save();
+        $id++;
       }
     }
-    $this->entities = entity_load_multiple($this->entity_type);
+    $this->entities = entity_load_multiple($this->entity_type, range(1, $id));
     foreach ($this->entities as $entity) {
       // Also keep track of the entities per bundle.
-      $this->entities_by_bundles[$entity->bundle()][$entity->id()] = $entity;
+      $this->entities_by_bundles[$entity->fttype][$entity->ftid] = $entity;
     }
   }
 
@@ -169,8 +193,8 @@ function testDeleteFieldInstance() {
     $factory = \Drupal::service('entity.query');
 
     // There are 10 entities of this bundle.
-    $found = $factory->get('entity_test')
-      ->condition('type', $bundle)
+    $found = $factory->get('test_entity')
+      ->condition('fttype', $bundle)
       ->execute();
     $this->assertEqual(count($found), 10, 'Correct number of entities found before deleting');
 
@@ -185,21 +209,21 @@ function testDeleteFieldInstance() {
     $this->assertEqual($instance['bundle'], $bundle, 'The deleted instance is for the correct bundle');
 
     // There are 0 entities of this bundle with non-deleted data.
-    $found = $factory->get('entity_test')
-      ->condition('type', $bundle)
+    $found = $factory->get('test_entity')
+      ->condition('fttype', $bundle)
       ->condition("$field_name.deleted", 0)
       ->execute();
     $this->assertFalse($found, 'No entities found after deleting');
 
     // There are 10 entities of this bundle when deleted fields are allowed, and
     // their values are correct.
-    $found = $factory->get('entity_test')
-      ->condition('type', $bundle)
+    $found = $factory->get('test_entity')
+      ->condition('fttype', $bundle)
       ->condition("$field_name.deleted", 1)
-      ->sort('id')
+      ->sort('ftid')
       ->execute();
     $ids = (object) array(
-      'entity_type' => 'entity_test',
+      'entity_type' => 'test_entity',
       'bundle' => $bundle,
     );
     $entities = array();
@@ -210,7 +234,7 @@ function testDeleteFieldInstance() {
     field_attach_load($this->entity_type, $entities, FIELD_LOAD_CURRENT, array('instance' => $instance));
     $this->assertEqual(count($found), 10, 'Correct number of entities found after deleting');
     foreach ($entities as $id => $entity) {
-      $this->assertEqual($this->entities[$id]->{$field->id()}->value, $entity->{$field->id()}[Language::LANGCODE_NOT_SPECIFIED][0]['value'], "Entity $id with deleted data loaded correctly");
+      $this->assertEqual($this->entities[$id]->{$field->id()}, $entity->{$field->id()}, "Entity $id with deleted data loaded correctly");
     }
   }
 
@@ -239,8 +263,8 @@ function testPurgeInstance() {
       field_purge_batch($batch_size);
 
       // There are $count deleted entities left.
-      $found = \Drupal::entityQuery('entity_test')
-        ->condition('type', $bundle)
+      $found = \Drupal::entityQuery('test_entity')
+        ->condition('fttype', $bundle)
         ->condition($field->id() . '.deleted', 1)
         ->execute();
       $this->assertEqual(count($found), $count, 'Correct number of entities found after purging 2');
@@ -251,7 +275,7 @@ function testPurgeInstance() {
     // for each entity in the bundle.
     $actual_hooks = field_test_memorize();
     $hooks = array();
-    $entities = $this->entities_by_bundles[$bundle];
+    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field->id());
     foreach ($entities as $id => $entity) {
       $hooks['field_test_field_load'][] = array($id => $entity);
       $hooks['field_test_field_delete'][] = $entity;
@@ -301,7 +325,7 @@ function testPurgeField() {
     // for each entity in the bundle.
     $actual_hooks = field_test_memorize();
     $hooks = array();
-    $entities = $this->entities_by_bundles[$bundle];
+    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field->id());
     foreach ($entities as $id => $entity) {
       $hooks['field_test_field_load'][] = array($id => $entity);
       $hooks['field_test_field_delete'][] = $entity;
@@ -330,7 +354,7 @@ function testPurgeField() {
     // Check hooks invocations (same as above, for the 2nd bundle).
     $actual_hooks = field_test_memorize();
     $hooks = array();
-    $entities = $this->entities_by_bundles[$bundle];
+    $entities = $this->convertToPartialEntities($this->entities_by_bundles[$bundle], $field->id());
     foreach ($entities as $id => $entity) {
       $hooks['field_test_field_load'][] = array($id => $entity);
       $hooks['field_test_field_delete'][] = $entity;
diff --git a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
index b7b7d58..72f9abe 100644
--- a/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/CrudTest.php
@@ -139,11 +139,11 @@ function testCreateField() {
     }
 
     // Check that field name can not be an entity key.
-    // "id" is known as an entity key from the "entity_test" type.
+    // "ftvid" is known as an entity key from the "test_entity" type.
     try {
       $field_definition = array(
         'type' => 'test_field',
-        'field_name' => 'id',
+        'field_name' => 'ftvid',
       );
       entity_create('field_entity', $field_definition)->save();
       $this->fail(t('Cannot create a field bearing the name of an entity key.'));
@@ -216,8 +216,8 @@ function testReadFields() {
     // Create an instance of the field.
     $instance_definition = array(
       'field_name' => $field_definition['field_name'],
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     );
     entity_create('field_instance', $instance_definition)->save();
   }
@@ -283,8 +283,8 @@ function testDeleteField() {
     // Create instances for each.
     $this->instance_definition = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     );
     entity_create('field_instance', $this->instance_definition)->save();
     $another_instance_definition = $this->instance_definition;
@@ -303,7 +303,7 @@ function testDeleteField() {
 
     // Make sure that this field's instance is marked as deleted when it is
     // specifically loaded.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($instance['deleted']), 'An instance for a deleted field is marked for deletion.');
 
     // Try to load the field normally and make sure it does not show up.
@@ -311,13 +311,13 @@ function testDeleteField() {
     $this->assertTrue(empty($field), 'A deleted field is not loaded by default.');
 
     // Try to load the instance normally and make sure it does not show up.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue(empty($instance), 'An instance for a deleted field is not loaded by default.');
 
     // Make sure the other field (and its field instance) are not deleted.
     $another_field = field_read_field($this->another_field['field_name']);
     $this->assertTrue(!empty($another_field) && empty($another_field['deleted']), 'A non-deleted field is not marked for deletion.');
-    $another_instance = field_read_instance('entity_test', $another_instance_definition['field_name'], $another_instance_definition['bundle']);
+    $another_instance = field_read_instance('test_entity', $another_instance_definition['field_name'], $another_instance_definition['bundle']);
     $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'An instance of a non-deleted field is not marked for deletion.');
 
     // Try to create a new field the same name as a deleted field and
@@ -326,22 +326,23 @@ function testDeleteField() {
     entity_create('field_instance', $this->instance_definition)->save();
     $field = field_read_field($this->field['field_name']);
     $this->assertTrue(!empty($field) && empty($field['deleted']), 'A new field with a previously used name is created.');
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new instance for a previously used field name is created.');
 
     // Save an entity with data for the field
-    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
+    $entity = field_test_create_entity(0, 0, $instance['bundle']);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $values[0]['value'] = mt_rand(1, 127);
-    $entity->{$field['field_name']}->value = $values[0]['value'];
+    $entity->{$field['field_name']}[$langcode] = $values;
+    $entity_type = 'test_entity';
     field_attach_insert($entity);
 
     // Verify the field is present on load
-    $entity = entity_create('entity_test', array('id' => 0, 'revision_id' => 0));
-    field_attach_load('entity_test', array(0 => $entity));
-    $this->assertIdentical(count($entity->{$field['field_name']}), count($values), "Data in previously deleted field saves and loads correctly");
+    $entity = field_test_create_entity(0, 0, $this->instance_definition['bundle']);
+    field_attach_load($entity_type, array(0 => $entity));
+    $this->assertIdentical(count($entity->{$field['field_name']}[$langcode]), count($values), "Data in previously deleted field saves and loads correctly");
     foreach ($values as $delta => $value) {
-      $this->assertEqual($entity->{$field['field_name']}[$delta]->value, $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
+      $this->assertEqual($entity->{$field['field_name']}[$langcode][$delta]['value'], $values[$delta]['value'], "Data in previously deleted field saves and loads correctly");
     }
   }
 
@@ -376,28 +377,28 @@ function testUpdateField() {
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'field_update',
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     ));
     $instance->save();
 
     do {
       // We need a unique ID for our entity. $cardinality will do.
       $id = $cardinality;
-      $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id));
+      $entity = field_test_create_entity($id, $id, $instance->bundle);
       // Fill in the entity with more values than $cardinality.
       for ($i = 0; $i < 20; $i++) {
-        $entity->field_update[$i]->value = $i;
+        $entity->field_update[Language::LANGCODE_NOT_SPECIFIED][$i]['value'] = $i;
       }
       // Save the entity.
       field_attach_insert($entity);
       // Load back and assert there are $cardinality number of values.
-      $entity = entity_create('entity_test', array('id' => $id, 'revision_id' => $id));
-      field_attach_load('entity_test', array($id => $entity));
-      $this->assertEqual(count($entity->field_update), $field->cardinality, 'Cardinality is kept');
+      $entity = field_test_create_entity($id, $id, $instance->bundle);
+      field_attach_load('test_entity', array($id => $entity));
+      $this->assertEqual(count($entity->field_update[Language::LANGCODE_NOT_SPECIFIED]), $field->cardinality, 'Cardinality is kept');
       // Now check the values themselves.
       for ($delta = 0; $delta < $cardinality; $delta++) {
-        $this->assertEqual($entity->field_update[$delta]->value, $delta, 'Value is kept');
+        $this->assertEqual($entity->field_update[Language::LANGCODE_NOT_SPECIFIED][$delta]['value'], $delta, 'Value is kept');
       }
       // Increase $cardinality and set the field cardinality to the new value.
       $field->cardinality = ++$cardinality;
diff --git a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
index 70195d3..57b917d 100644
--- a/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/DisplayApiTest.php
@@ -40,7 +40,7 @@ class DisplayApiTest extends FieldUnitTestBase {
   protected $display_options;
 
   /**
-   * The test entity.
+   * The field display options to use in this test.
    *
    * @var \Drupal\Core\Entity\EntityInterface
    */
@@ -76,8 +76,8 @@ function setUp() {
     );
     $instance = array(
       'field_name' => $this->field_name,
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
       'label' => $this->label,
     );
 
@@ -109,9 +109,10 @@ function setUp() {
 
     // Create an entity with values.
     $this->values = $this->_generateTestFieldValues($this->cardinality);
-    $this->entity = entity_create('entity_test', array());
-    $this->entity->{$this->field_name}->setValue($this->values);
-    $this->entity->save();
+    $this->entity = field_test_create_entity();
+    $this->is_new = TRUE;
+    $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED] = $this->values;
+    field_test_entity_save($this->entity);
   }
 
   /**
@@ -196,7 +197,7 @@ function testFieldViewValue() {
     $settings = field_info_formatter_settings('field_test_default');
     $setting = $settings['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $item = $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED][$delta];
       $output = field_view_value($this->entity, $this->field_name, $item);
       $this->content = drupal_render($output);
       $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
@@ -212,7 +213,7 @@ function testFieldViewValue() {
     $setting = $display['settings']['test_formatter_setting_multiple'];
     $array = array();
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $item = $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED][$delta];
       $output = field_view_value($this->entity, $this->field_name, $item, $display);
       $this->content = drupal_render($output);
       $this->assertText($setting . '|0:' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
@@ -228,7 +229,7 @@ function testFieldViewValue() {
     $setting = $display['settings']['test_formatter_setting_additional'];
     $array = array();
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $item = $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED][$delta];
       $output = field_view_value($this->entity, $this->field_name, $item, $display);
       $this->content = drupal_render($output);
       $this->assertText($setting . '|' . $value['value'] . '|' . ($value['value'] + 1), format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
@@ -238,7 +239,7 @@ function testFieldViewValue() {
     // used.
     $setting = $this->display_options['teaser']['settings']['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $item = $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED][$delta];
       $output = field_view_value($this->entity, $this->field_name, $item, 'teaser');
       $this->content = drupal_render($output);
       $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
@@ -248,7 +249,7 @@ function testFieldViewValue() {
     // are used.
     $setting = $this->display_options['default']['settings']['test_formatter_setting'];
     foreach ($this->values as $delta => $value) {
-      $item = $this->entity->{$this->field_name}[$delta]->getValue();
+      $item = $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED][$delta];
       $output = field_view_value($this->entity, $this->field_name, $item, 'unknown_view_mode');
       $this->content = drupal_render($output);
       $this->assertText($setting . '|' . $value['value'], format_string('Value @delta was displayed with expected setting.', array('@delta' => $delta)));
@@ -277,8 +278,8 @@ function testFieldEmpty() {
     $this->assertNoText($display['settings']['test_empty_string']);
 
     // Now remove the values from the test field and retest.
-    $this->entity->{$this->field_name} = array();
-    $this->entity->save();
+    $this->entity->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED] = array();
+    field_test_entity_save($this->entity);
     $output = field_view_field($this->entity, $this->field_name, $display);
     $view = drupal_render($output);
     $this->content = $view;
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
index 4739d5f..cdbfc6a 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachOtherTest.php
@@ -47,16 +47,16 @@ public function setUp() {
   function testFieldAttachView() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'entity_test';
-    $entity_init = entity_create($entity_type, array());
+    $entity_type = 'test_entity';
+    $entity_init = field_test_create_entity();
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $options = array('field_name' => $this->field_name_2);
 
     // Populate values to be displayed.
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity_init->{$this->field_name}->setValue($values);
+    $entity_init->{$this->field_name}[$langcode] = $values;
     $values_2 = $this->_generateTestFieldValues($this->field_2['cardinality']);
-    $entity_init->{$this->field_name_2}->setValue($values_2);
+    $entity_init->{$this->field_name_2}[$langcode] = $values_2;
 
     // Simple formatter, label displayed.
     $entity = clone($entity_init);
@@ -84,9 +84,9 @@ function testFieldAttachView() {
     $display->setComponent($this->field_2['field_name'], $display_options_2);
 
     // View all fields.
-    field_attach_prepare_view($entity_type, array($entity->id() => $entity), $displays);
-    $content = field_attach_view($entity, $display);
-    $output = drupal_render($content);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
+    $entity->content = field_attach_view($entity, $display);
+    $output = drupal_render($entity->content);
     $this->content = $output;
     $this->assertRaw($this->instance['label'], "First field's label is displayed.");
     foreach ($values as $delta => $value) {
@@ -103,7 +103,7 @@ function testFieldAttachView() {
     $entity = clone($entity_init);
     $display_options['label'] = 'hidden';
     $display->setComponent($this->field['field_name'], $display_options);
-    field_attach_prepare_view($entity_type, array($entity->id() => $entity), $displays);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $this->content = $output;
@@ -112,7 +112,7 @@ function testFieldAttachView() {
     // Field hidden.
     $entity = clone($entity_init);
     $display->removeComponent($this->field['field_name']);
-    field_attach_prepare_view($entity_type, array($entity->id() => $entity), $displays);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $this->content = $output;
@@ -131,7 +131,7 @@ function testFieldAttachView() {
         'test_formatter_setting_multiple' => $formatter_setting,
       ),
     ));
-    field_attach_prepare_view($entity_type, array($entity->id() => $entity), $displays);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $expected_output = $formatter_setting;
@@ -151,7 +151,7 @@ function testFieldAttachView() {
         'test_formatter_setting_additional' => $formatter_setting,
       ),
     ));
-    field_attach_prepare_view($entity_type, array($entity->id() => $entity), $displays);
+    field_attach_prepare_view($entity_type, array($entity->ftid => $entity), $displays);
     $entity->content = field_attach_view($entity, $display);
     $output = drupal_render($entity->content);
     $this->content = $output;
@@ -180,22 +180,23 @@ function testFieldAttachView() {
    * Tests the 'multiple entity' behavior of field_attach_prepare_view().
    */
   function testFieldAttachPrepareViewMultiple() {
-    $entity_type = 'entity_test';
+    $entity_type = 'test_entity';
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Set the instance to be hidden.
-    $display = entity_get_display('entity_test', 'entity_test', 'full')
+    $display = entity_get_display('test_entity', 'test_bundle', 'full')
       ->removeComponent($this->field['field_name']);
 
     // Set up a second instance on another bundle, with a formatter that uses
     // hook_field_formatter_prepare_view().
-    entity_test_create_bundle('test_bundle_2');
+    field_test_create_bundle('test_bundle_2');
     $formatter_setting = $this->randomName();
     $instance_definition = $this->instance_definition;
     $instance_definition['bundle'] = 'test_bundle_2';
     $this->instance2 = entity_create('field_instance', $instance_definition);
     $this->instance2->save();
 
-    $display_2 = entity_get_display('entity_test', 'test_bundle_2', 'full')
+    $display_2 = entity_get_display('test_entity', 'test_bundle_2', 'full')
       ->setComponent($this->field['field_name'], array(
         'type' => 'field_test_with_prepare_view',
         'settings' => array(
@@ -203,32 +204,32 @@ function testFieldAttachPrepareViewMultiple() {
         ),
       ));
 
-    $displays = array('entity_test' => $display, 'test_bundle_2' => $display_2);
+    $displays = array('test_bundle' => $display, 'test_bundle_2' => $display_2);
 
     // Create one entity in each bundle.
-    $entity1_init = entity_create('entity_test', array('id' => 1, 'type' => 'entity_test'));
+    $entity1_init = field_test_create_entity(1, 1, 'test_bundle');
     $values1 = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity1_init->{$this->field_name}->setValue($values1);
+    $entity1_init->{$this->field_name}[$langcode] = $values1;
 
-    $entity2_init = entity_create('entity_test', array('id' => 2, 'type' => 'test_bundle_2'));
+    $entity2_init = field_test_create_entity(2, 2, 'test_bundle_2');
     $values2 = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity2_init->{$this->field_name}->setValue($values2);
+    $entity2_init->{$this->field_name}[$langcode] = $values2;
 
     // Run prepare_view, and check that the entities come out as expected.
     $entity1 = clone($entity1_init);
     $entity2 = clone($entity2_init);
-    $entities = array($entity1->id() => $entity1, $entity2->id() => $entity2);
+    $entities = array($entity1->ftid => $entity1, $entity2->ftid => $entity2);
     field_attach_prepare_view($entity_type, $entities, $displays);
-    $this->assertFalse(isset($entity1->{$this->field_name}->additional_formatter_value), 'Entity 1 did not run through the prepare_view hook.');
-    $this->assertTrue(isset($entity2->{$this->field_name}->additional_formatter_value), 'Entity 2 ran through the prepare_view hook.');
+    $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.');
+    $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.');
 
     // Same thing, reversed order.
     $entity1 = clone($entity1_init);
     $entity2 = clone($entity2_init);
-    $entities = array($entity1->id() => $entity1, $entity2->id() => $entity2);
+    $entities = array($entity1->ftid => $entity1, $entity2->ftid => $entity2);
     field_attach_prepare_view($entity_type, $entities, $displays);
-    $this->assertFalse(isset($entity1->{$this->field_name}->additional_formatter_value), 'Entity 1 did not run through the prepare_view hook.');
-    $this->assertTrue(isset($entity2->{$this->field_name}->additional_formatter_value), 'Entity 2 ran through the prepare_view hook.');
+    $this->assertFalse(isset($entity1->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 1 did not run through the prepare_view hook.');
+    $this->assertTrue(isset($entity2->{$this->field_name}[$langcode][0]['additional_formatter_value']), 'Entity 2 ran through the prepare_view hook.');
   }
 
   /**
@@ -236,96 +237,92 @@ function testFieldAttachPrepareViewMultiple() {
    */
   function testFieldAttachCache() {
     // Initialize random values and a test entity.
-    $entity_init = entity_create('entity_test', array('id' => 1, 'revision_id' => 1, 'type' => $this->instance['bundle']));
+    $entity_init = field_test_create_entity(1, 1, $this->instance['bundle']);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
 
     // Non-cacheable entity type.
-    $entity_type = 'entity_test';
-    $cid = "field:$entity_type:" . $entity_init->id();
+    $entity_type = 'test_entity';
+    $cid = "field:$entity_type:{$entity_init->ftid}";
 
     // Check that no initial cache entry is present.
     $this->assertFalse(cache('field')->get($cid), 'Non-cached: no initial cache entry');
 
     // Save, and check that no cache entry is present.
     $entity = clone($entity_init);
-    $entity->{$this->field_name}->setValue($values);
+    $entity->{$this->field_name}[$langcode] = $values;
     field_attach_insert($entity);
     $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on insert');
 
     // Load, and check that no cache entry is present.
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    field_attach_load($entity_type, array($entity->ftid => $entity));
     $this->assertFalse(cache('field')->get($cid), 'Non-cached: no cache entry on load');
 
 
     // Cacheable entity type.
-    $entity_type = 'entity_test_cache';
-    $cid = "field:$entity_type:" . $entity_init->id();
+    $entity_type = 'test_cacheable_entity';
+    $entity_init = entity_create($entity_type, array(
+      'ftid' => 1,
+      'ftvid' => 1,
+      'fttype' => $this->instance['bundle'],
+    ));
+    $cid = "field:$entity_type:{$entity_init->ftid}";
     $instance_definition = $this->instance_definition;
     $instance_definition['entity_type'] = $entity_type;
-    $instance_definition['bundle'] = $entity_type;
     entity_create('field_instance', $instance_definition)->save();
 
-    entity_info_cache_clear();
-
-    $entity_init = entity_create($entity_type, array(
-      'id' => 1,
-      'revision_id' => 1,
-      'type' => $entity_type,
-    ));
-
     // Check that no initial cache entry is present.
     $this->assertFalse(cache('field')->get($cid), 'Cached: no initial cache entry');
 
     // Save, and check that no cache entry is present.
     $entity = clone($entity_init);
-    $entity->{$this->field_name} = $values;
+    $entity->{$this->field_name}[$langcode] = $values;
     field_attach_insert($entity);
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on insert');
 
     // Load a single field, and check that no cache entry is present.
     $entity = clone($entity_init);
     $instance = field_info_instance($entity->entityType(), $this->field_name, $entity->bundle());
-    field_attach_load($entity_type, array($entity->id() => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance));
+    field_attach_load($entity_type, array($entity->ftid => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance));
     $cache = cache('field')->get($cid);
     $this->assertFalse($cache, 'Cached: no cache entry on loading a single field');
 
     // Load, and check that a cache entry is present with the expected values.
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    field_attach_load($entity_type, array($entity->ftid => $entity));
     $cache = cache('field')->get($cid);
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
     // Update with different values, and check that the cache entry is wiped.
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity = clone($entity_init);
-    $entity->{$this->field_name} = $values;
+    $entity->{$this->field_name}[$langcode] = $values;
     field_attach_update($entity);
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on update');
 
     // Load, and check that a cache entry is present with the expected values.
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    field_attach_load($entity_type, array($entity->ftid => $entity));
     $cache = cache('field')->get($cid);
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
     // Create a new revision, and check that the cache entry is wiped.
     $entity_init = entity_create($entity_type, array(
-      'id' => 1,
-      'revision_id' => 2,
-      'type' => $entity_type,
+      'ftid' => 1,
+      'ftvid' => 2,
+      'fttype' => $this->instance['bundle'],
     ));
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
     $entity = clone($entity_init);
-    $entity->{$this->field_name} = $values;
+    $entity->{$this->field_name}[$langcode] = $values;
     field_attach_update($entity);
     $cache = cache('field')->get($cid);
     $this->assertFalse(cache('field')->get($cid), 'Cached: no cache entry on new revision creation');
 
     // Load, and check that a cache entry is present with the expected values.
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    field_attach_load($entity_type, array($entity->ftid => $entity));
     $cache = cache('field')->get($cid);
     $this->assertEqual($cache->data[$this->field_name][$langcode], $values, 'Cached: correct cache entry on load');
 
@@ -343,8 +340,8 @@ function testFieldAttachCache() {
   function testFieldAttachForm() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'entity_test';
-    $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $this->instance['bundle']));
+    $entity_type = 'test_entity';
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // When generating form for all fields.
@@ -385,8 +382,8 @@ function testFieldAttachForm() {
   function testFieldAttachExtractFormValues() {
     $this->createFieldWithInstance('_2');
 
-    $entity_type = 'entity_test';
-    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $this->instance['bundle']));
+    $entity_type = 'test_entity';
+    $entity_init = field_test_create_entity(0, 0, $this->instance['bundle']);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Build the form for all fields.
@@ -444,13 +441,13 @@ function testFieldAttachExtractFormValues() {
         $expected_values[] = array('value' => $values[$key]['value']);
       }
     }
-    $this->assertIdentical($entity->{$this->field_name}->getValue(), $expected_values, 'Submit filters empty values');
+    $this->assertIdentical($entity->{$this->field_name}[$langcode], $expected_values, 'Submit filters empty values');
     foreach ($weights_2 as $key => $value) {
       if ($key != 1) {
         $expected_values_2[] = array('value' => $values_2[$key]['value']);
       }
     }
-    $this->assertIdentical($entity->{$this->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values');
+    $this->assertIdentical($entity->{$this->field_name_2}[$langcode], $expected_values_2, 'Submit filters empty values');
 
     // Call field_attach_extract_form_values() for a single field (the second field).
     $options = array('field_name' => $this->field_name_2);
@@ -462,8 +459,8 @@ function testFieldAttachExtractFormValues() {
         $expected_values_2[] = array('value' => $values_2[$key]['value']);
       }
     }
-    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'The first field does is empty in the entity object');
-    $this->assertIdentical($entity->{$this->field_name_2}->getValue(), $expected_values_2, 'Submit filters empty values');
+    $this->assertFalse(isset($entity->{$this->field_name}), 'The first field does not exist in the entity object');
+    $this->assertIdentical($entity->{$this->field_name_2}[$langcode], $expected_values_2, 'Submit filters empty values');
   }
 
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
index e5f28d0..5deefdf 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldAttachStorageTest.php
@@ -41,7 +41,7 @@ public static function getInfo() {
 
   public function setUp() {
     parent::setUp();
-    $this->installSchema('entity_test', array('entity_test_rev', 'entity_test_rev_revision'));
+    $this->createFieldWithInstance();
   }
 
   /**
@@ -51,57 +51,58 @@ public function setUp() {
    * updates random field data and then loads and verifies the data.
    */
   function testFieldAttachSaveLoad() {
-    $entity_type = 'entity_test_rev';
-    $this->createFieldWithInstance('', $entity_type);
-
     // Configure the instance so that we test hook_field_load() (see
     // field_test_field_load() in field_test.module).
     $this->instance['settings']['test_hook_field_load'] = TRUE;
     $this->instance->save();
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+
+    $entity_type = 'test_entity';
+    $values = array();
 
     // TODO : test empty values filtering and "compression" (store consecutive deltas).
+
     // Preparation: create three revisions and store them in $revision array.
-    $values = array();
     for ($revision_id = 0; $revision_id < 3; $revision_id++) {
-      $revision[$revision_id] = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id));
+      $revision[$revision_id] = field_test_create_entity(0, $revision_id, $this->instance['bundle']);
       // Note: we try to insert one extra value.
       $values[$revision_id] = $this->_generateTestFieldValues($this->field['cardinality'] + 1);
       $current_revision = $revision_id;
       // If this is the first revision do an insert.
       if (!$revision_id) {
-        $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]);
+        $revision[$revision_id]->{$this->field_name}[$langcode] = $values[$revision_id];
         field_attach_insert($revision[$revision_id]);
       }
       else {
         // Otherwise do an update.
-        $revision[$revision_id]->{$this->field_name}->setValue($values[$revision_id]);
+        $revision[$revision_id]->{$this->field_name}[$langcode] = $values[$revision_id];
         field_attach_update($revision[$revision_id]);
       }
     }
 
     // Confirm current revision loads the correct data.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0));
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
     field_attach_load($entity_type, array(0 => $entity));
     // Number of values per field loaded equals the field cardinality.
-    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], 'Current revision: expected number of values');
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], 'Current revision: expected number of values');
     for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
       // The field value loaded matches the one inserted or updated.
-      $this->assertEqual($entity->{$this->field_name}[$delta]->value , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
+      $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'] , $values[$current_revision][$delta]['value'], format_string('Current revision: expected value %delta was found.', array('%delta' => $delta)));
       // The value added in hook_field_load() is found.
-      $this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
+      $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['additional_key'], 'additional_value', format_string('Current revision: extra information for value %delta was found', array('%delta' => $delta)));
     }
 
     // Confirm each revision loads the correct data.
     foreach (array_keys($revision) as $revision_id) {
-      $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => $revision_id));
+      $entity = field_test_create_entity(0, $revision_id, $this->instance['bundle']);
       field_attach_load_revision($entity_type, array(0 => $entity));
       // Number of values per field loaded equals the field cardinality.
-      $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
+      $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], format_string('Revision %revision_id: expected number of values.', array('%revision_id' => $revision_id)));
       for ($delta = 0; $delta < $this->field['cardinality']; $delta++) {
         // The field value loaded matches the one inserted or updated.
-        $this->assertEqual($entity->{$this->field_name}[$delta]->value, $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
+        $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $values[$revision_id][$delta]['value'], format_string('Revision %revision_id: expected value %delta was found.', array('%revision_id' => $revision_id, '%delta' => $delta)));
         // The value added in hook_field_load() is found.
-        $this->assertEqual($entity->{$this->field_name}[$delta]->additional_key, 'additional_value', format_string('Revision %revision_id: extra information for value %delta was found', array('%revision_id' => $revision_id, '%delta' => $delta)));
+        $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['additional_key'], 'additional_value', format_string('Revision %revision_id: extra information for value %delta was found', array('%revision_id' => $revision_id, '%delta' => $delta)));
       }
     }
   }
@@ -110,15 +111,16 @@ function testFieldAttachSaveLoad() {
    * Test the 'multiple' load feature.
    */
   function testFieldAttachLoadMultiple() {
-    $entity_type = 'entity_test';
+    $entity_type = 'test_entity';
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Define 2 bundles.
     $bundles = array(
       1 => 'test_bundle_1',
       2 => 'test_bundle_2',
     );
-    entity_test_create_bundle($bundles[1]);
-    entity_test_create_bundle($bundles[2]);
+    field_test_create_bundle($bundles[1]);
+    field_test_create_bundle($bundles[2]);
     // Define 3 fields:
     // - field_1 is in bundle_1 and bundle_2,
     // - field_2 is in bundle_1,
@@ -136,7 +138,7 @@ function testFieldAttachLoadMultiple() {
       foreach ($field_bundles_map[$i] as $bundle) {
         entity_create('field_instance', array(
           'field_name' => $field_names[$i],
-          'entity_type' => $entity_type,
+          'entity_type' => 'test_entity',
           'bundle' => $bundles[$bundle],
           'settings' => array(
             // Configure the instance so that we test hook_field_load()
@@ -149,12 +151,12 @@ function testFieldAttachLoadMultiple() {
 
     // Create one test entity per bundle, with random values.
     foreach ($bundles as $index => $bundle) {
-      $entities[$index] = entity_create($entity_type, array('id' => $index, 'revision_id' => $index, 'type' => $bundle));
+      $entities[$index] = field_test_create_entity($index, $index, $bundle);
       $entity = clone($entities[$index]);
-      $instances = field_info_instances($entity_type, $bundle);
+      $instances = field_info_instances('test_entity', $bundle);
       foreach ($instances as $field_name => $instance) {
         $values[$index][$field_name] = mt_rand(1, 127);
-        $entity->$field_name->setValue(array('value' => $values[$index][$field_name]));
+        $entity->$field_name = array($langcode => array(array('value' => $values[$index][$field_name])));
       }
       field_attach_insert($entity);
     }
@@ -165,19 +167,19 @@ function testFieldAttachLoadMultiple() {
       $instances = field_info_instances($entity_type, $bundles[$index]);
       foreach ($instances as $field_name => $instance) {
         // The field value loaded matches the one inserted.
-        $this->assertEqual($entity->{$field_name}->value, $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index)));
+        $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $values[$index][$field_name], format_string('Entity %index: expected value was found.', array('%index' => $index)));
         // The value added in hook_field_load() is found.
-        $this->assertEqual($entity->{$field_name}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index)));
+        $this->assertEqual($entity->{$field_name}[$langcode][0]['additional_key'], 'additional_value', format_string('Entity %index: extra information was found', array('%index' => $index)));
       }
     }
 
     // Check that the single-field load option works.
-    $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $bundles[1]));
+    $entity = field_test_create_entity(1, 1, $bundles[1]);
     $instance = field_info_instance($entity->entityType(), $field_names[1], $entity->bundle());
     field_attach_load($entity_type, array(1 => $entity), FIELD_LOAD_CURRENT, array('instance' => $instance));
-    $this->assertEqual($entity->{$field_names[1]}->value, $values[1][$field_names[1]], format_string('Entity %index: expected value was found.', array('%index' => 1)));
-    $this->assertEqual($entity->{$field_names[1]}->additional_key, 'additional_value', format_string('Entity %index: extra information was found', array('%index' => 1)));
-    $this->assert(empty($entity->{$field_names[2]}->value), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 2, '%field_name' => $field_names[2])));
+    $this->assertEqual($entity->{$field_names[1]}[$langcode][0]['value'], $values[1][$field_names[1]], format_string('Entity %index: expected value was found.', array('%index' => 1)));
+    $this->assertEqual($entity->{$field_names[1]}[$langcode][0]['additional_key'], 'additional_value', format_string('Entity %index: extra information was found', array('%index' => 1)));
+    $this->assert(!isset($entity->{$field_names[2]}), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 2, '%field_name' => $field_names[2])));
     $this->assert(!isset($entity->{$field_names[3]}), format_string('Entity %index: field %field_name is not loaded.', array('%index' => 3, '%field_name' => $field_names[3])));
   }
 
@@ -185,7 +187,8 @@ function testFieldAttachLoadMultiple() {
    * Test saving and loading fields using different storage backends.
    */
   function testFieldAttachSaveLoadDifferentStorage() {
-    $entity_type = 'entity_test';
+    $entity_type = 'test_entity';
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Create two fields using different storage backends, and their instances.
     $fields = array(
@@ -206,28 +209,28 @@ function testFieldAttachSaveLoadDifferentStorage() {
       entity_create('field_entity', $field)->save();
       $instance = array(
         'field_name' => $field['field_name'],
-        'entity_type' => $entity_type,
-        'bundle' => $entity_type,
+        'entity_type' => 'test_entity',
+        'bundle' => 'test_bundle',
       );
       entity_create('field_instance', $instance)->save();
     }
 
-    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1));
+    $entity_init = field_test_create_entity();
 
     // Create entity and insert random values.
     $entity = clone($entity_init);
     $values = array();
     foreach ($fields as $field) {
       $values[$field['field_name']] = $this->_generateTestFieldValues($this->field['cardinality']);
-      $entity->{$field['field_name']} = $values[$field['field_name']];
+      $entity->{$field['field_name']}[$langcode] = $values[$field['field_name']];
     }
     field_attach_insert($entity);
 
     // Check that values are loaded as expected.
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
+    field_attach_load($entity_type, array($entity->ftid => $entity));
     foreach ($fields as $field) {
-      $this->assertEqual($values[$field['field_name']], $entity->{$field['field_name']}->getValue(), format_string('%storage storage: expected values were found.', array('%storage' => $field['storage']['type'])));
+      $this->assertEqual($values[$field['field_name']], $entity->{$field['field_name']}[$langcode], format_string('%storage storage: expected values were found.', array('%storage' => $field['storage']['type'])));
     }
   }
 
@@ -247,8 +250,8 @@ function testFieldStorageDetailsAlter() {
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => $field_name,
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     ));
     $instance->save();
 
@@ -271,13 +274,20 @@ function testFieldStorageDetailsAlter() {
   }
 
   /**
-   * Tests insert and update with empty or NULL fields.
+   * Tests insert and update with missing or NULL fields.
    */
-  function testFieldAttachSaveEmptyData() {
-    $entity_type = 'entity_test_rev';
-    $this->createFieldWithInstance('', $entity_type);
+  function testFieldAttachSaveMissingData() {
+    $entity_type = 'test_entity';
+    $entity_init = field_test_create_entity();
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+
+    // Insert: Field is missing.
+    $entity = clone($entity_init);
+    field_attach_insert($entity);
 
-    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1));
+    $entity = clone($entity_init);
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertTrue(empty($entity->{$this->field_name}), 'Insert: missing field results in no value saved');
 
     // Insert: Field is NULL.
     field_cache_clear();
@@ -286,19 +296,28 @@ function testFieldAttachSaveEmptyData() {
     field_attach_insert($entity);
 
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved');
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertTrue(empty($entity->{$this->field_name}), 'Insert: NULL field results in no value saved');
 
     // Add some real data.
     field_cache_clear();
     $entity = clone($entity_init);
     $values = $this->_generateTestFieldValues(1);
-    $entity->{$this->field_name} = $values;
+    $entity->{$this->field_name}[$langcode] = $values;
     field_attach_insert($entity);
 
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved');
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertEqual($entity->{$this->field_name}[$langcode], $values, 'Field data saved');
+
+    // Update: Field is missing. Data should survive.
+    field_cache_clear();
+    $entity = clone($entity_init);
+    field_attach_update($entity);
+
+    $entity = clone($entity_init);
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertEqual($entity->{$this->field_name}[$langcode], $values, 'Update: missing field leaves existing values in place');
 
     // Update: Field is NULL. Data should be wiped.
     field_cache_clear();
@@ -307,19 +326,19 @@ function testFieldAttachSaveEmptyData() {
     field_attach_update($entity);
 
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: NULL field removes existing values');
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertTrue(empty($entity->{$this->field_name}), 'Update: NULL field removes existing values');
 
     // Re-add some data.
     field_cache_clear();
     $entity = clone($entity_init);
     $values = $this->_generateTestFieldValues(1);
-    $entity->{$this->field_name} = $values;
+    $entity->{$this->field_name}[$langcode] = $values;
     field_attach_update($entity);
 
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertEqual($entity->{$this->field_name}->getValue(), $values, 'Field data saved');
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertEqual($entity->{$this->field_name}[$langcode], $values, 'Field data saved');
 
     // Update: Field is empty array. Data should be wiped.
     field_cache_clear();
@@ -328,147 +347,152 @@ function testFieldAttachSaveEmptyData() {
     field_attach_update($entity);
 
     $entity = clone($entity_init);
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Update: empty array removes existing values');
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertTrue(empty($entity->{$this->field_name}), 'Update: empty array removes existing values');
   }
 
   /**
-   * Test insert with empty or NULL fields, with default value.
+   * Test insert with missing or NULL fields, with default value.
    */
-  function testFieldAttachSaveEmptyDataDefaultValue() {
-    $entity_type = 'entity_test_rev';
-    $this->createFieldWithInstance('', $entity_type);
-
+  function testFieldAttachSaveMissingDataDefaultValue() {
     // Add a default value function.
     $this->instance['default_value_function'] = 'field_test_default_value';
     $this->instance->save();
 
     // Verify that fields are populated with default values.
-    $entity_init = entity_create($entity_type, array('id' => 1, 'revision_id' => 1));
+    $entity_type = 'test_entity';
+    $entity_init = field_test_create_entity();
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $default = field_test_default_value($entity_init, $this->field, $this->instance);
-    $this->assertEqual($entity_init->{$this->field_name}->getValue(), $default, 'Default field value correctly populated.');
+    $this->assertEqual($entity_init->{$this->field_name}[$langcode], $default, 'Default field value correctly populated.');
 
     // Insert: Field is NULL.
     $entity = clone($entity_init);
-    $entity->getBCEntity()->{$this->field_name} = NULL;
+    $entity->{$this->field_name}[$langcode] = NULL;
+    field_attach_insert($entity);
+
+    $entity = clone($entity_init);
+    $entity->{$this->field_name} = array();
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertTrue(empty($entity->{$this->field_name}[$langcode]), 'Insert: NULL field results in no value saved');
+
+    // Insert: Field is missing.
+    field_cache_clear();
+    $entity = clone($entity_init);
     field_attach_insert($entity);
 
     $entity = clone($entity_init);
-    $entity->getBCEntity()->{$this->field_name} = array();
-    field_attach_load($entity_type, array($entity->id() => $entity));
-    $this->assertTrue($entity->{$this->field_name}->isEmpty(), 'Insert: NULL field results in no value saved');
+    $entity->{$this->field_name} = array();
+    field_attach_load($entity_type, array($entity->ftid => $entity));
+    $this->assertEqual($entity->{$this->field_name}[$langcode], $default, 'Insert: missing field results in default value saved');
 
     // Verify that prepopulated field values are not overwritten by defaults.
     $value = array(array('value' => $default[0]['value'] - mt_rand(1, 127)));
-    $entity = entity_create($entity_type, array('type' => $entity_init->bundle(), $this->field_name => $value));
-    $this->assertEqual($entity->{$this->field_name}->getValue(), $value, 'Prepopulated field value correctly maintained.');
+    $entity = entity_create('test_entity', array('fttype' => $entity_init->bundle(), $this->field_name => array($langcode => $value)));
+    $this->assertEqual($entity->{$this->field_name}[$langcode], $value, 'Prepopulated field value correctly maintained.');
   }
 
   /**
    * Test field_attach_delete().
    */
   function testFieldAttachDelete() {
-    $entity_type = 'entity_test_rev';
-    $this->createFieldWithInstance('', $entity_type);
-    $rev[0] = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity_type = 'test_entity';
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
+    $rev[0] = field_test_create_entity(0, 0, $this->instance['bundle']);
 
     // Create revision 0
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $rev[0]->{$this->field_name} = $values;
+    $rev[0]->{$this->field_name}[$langcode] = $values;
     field_attach_insert($rev[0]);
 
     // Create revision 1
-    $rev[1] = entity_create($entity_type, array('id' => 0, 'revision_id' => 1, 'type' => $this->instance['bundle']));
-    $rev[1]->{$this->field_name} = $values;
+    $rev[1] = field_test_create_entity(0, 1, $this->instance['bundle']);
+    $rev[1]->{$this->field_name}[$langcode] = $values;
     field_attach_update($rev[1]);
 
     // Create revision 2
-    $rev[2] = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle']));
-    $rev[2]->{$this->field_name} = $values;
+    $rev[2] = field_test_create_entity(0, 2, $this->instance['bundle']);
+    $rev[2]->{$this->field_name}[$langcode] = $values;
     field_attach_update($rev[2]);
 
     // Confirm each revision loads
     foreach (array_keys($rev) as $vid) {
-      $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle']));
+      $read = field_test_create_entity(0, $vid, $this->instance['bundle']);
       field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
+      $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
     }
 
     // Delete revision 1, confirm the other two still load.
     field_attach_delete_revision($rev[1]);
     foreach (array(0, 2) as $vid) {
-      $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle']));
+      $read = field_test_create_entity(0, $vid, $this->instance['bundle']);
       field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
+      $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity revision $vid has {$this->field['cardinality']} values.");
     }
 
     // Confirm the current revision still loads
-    $read = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle']));
+    $read = field_test_create_entity(0, 2, $this->instance['bundle']);
     field_attach_load($entity_type, array(0 => $read));
-    $this->assertEqual(count($read->{$this->field_name}), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
+    $this->assertEqual(count($read->{$this->field_name}[$langcode]), $this->field['cardinality'], "The test entity current revision has {$this->field['cardinality']} values.");
 
     // Delete all field data, confirm nothing loads
     field_attach_delete($rev[2]);
     foreach (array(0, 1, 2) as $vid) {
-      $read = entity_create($entity_type, array('id' => 0, 'revision_id' => $vid, 'type' => $this->instance['bundle']));
+      $read = field_test_create_entity(0, $vid, $this->instance['bundle']);
       field_attach_load_revision($entity_type, array(0 => $read));
-      $this->assertIdentical($read->{$this->field_name}[0]->getValue(), array(), "The test entity revision $vid is deleted.");
+      $this->assertIdentical($read->{$this->field_name}, array(), "The test entity revision $vid is deleted.");
     }
-    $read = entity_create($entity_type, array('id' => 0, 'revision_id' => 2, 'type' => $this->instance['bundle']));
+    $read = field_test_create_entity(0, 2, $this->instance['bundle']);
     field_attach_load($entity_type, array(0 => $read));
-    $this->assertIdentical($read->{$this->field_name}[0]->getValue(), array(), 'The test entity current revision is deleted.');
+    $this->assertIdentical($read->{$this->field_name}, array(), 'The test entity current revision is deleted.');
   }
 
   /**
    * Test entity_bundle_create() and entity_bundle_rename().
    */
   function testEntityCreateRenameBundle() {
-    $entity_type = 'entity_test_rev';
-    $this->createFieldWithInstance('', $entity_type);
-
     // Create a new bundle.
     $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
-    entity_test_create_bundle($new_bundle, NULL, $entity_type);
+    field_test_create_bundle($new_bundle);
 
     // Add an instance to that bundle.
     $this->instance_definition['bundle'] = $new_bundle;
     entity_create('field_instance', $this->instance_definition)->save();
 
     // Save an entity with data in the field.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity->{$this->field_name} = $values;
+    $entity->{$this->field_name}[$langcode] = $values;
+    $entity_type = 'test_entity';
     field_attach_insert($entity);
 
     // Verify the field data is present on load.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
     field_attach_load($entity_type, array(0 => $entity));
-    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Data is retrieved for the new bundle");
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], "Data is retrieved for the new bundle");
 
     // Rename the bundle.
     $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
-    entity_test_rename_bundle($this->instance_definition['bundle'], $new_bundle, $entity_type);
+    field_test_rename_bundle($this->instance['bundle'], $new_bundle);
 
     // Check that the instance definition has been updated.
     $this->instance = field_info_instance($entity_type, $this->field_name, $new_bundle);
     $this->assertIdentical($this->instance['bundle'], $new_bundle, "Bundle name has been updated in the instance.");
 
     // Verify the field data is present on load.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = field_test_create_entity(0, 0, $new_bundle);
     field_attach_load($entity_type, array(0 => $entity));
-    $this->assertEqual(count($entity->{$this->field_name}), $this->field['cardinality'], "Bundle name has been updated in the field storage");
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), $this->field['cardinality'], "Bundle name has been updated in the field storage");
   }
 
   /**
    * Test entity_bundle_delete().
    */
   function testEntityDeleteBundle() {
-    $entity_type = 'entity_test_rev';
-    $this->createFieldWithInstance('', $entity_type);
-
     // Create a new bundle.
     $new_bundle = 'test_bundle_' . drupal_strtolower($this->randomName());
-    entity_test_create_bundle($new_bundle, NULL, $entity_type);
+    field_test_create_bundle($new_bundle);
 
     // Add an instance to that bundle.
     $this->instance_definition['bundle'] = $new_bundle;
@@ -480,7 +504,7 @@ function testEntityDeleteBundle() {
     entity_create('field_entity', $field)->save();
     $instance = array(
       'field_name' => $field_name,
-      'entity_type' => $entity_type,
+      'entity_type' => 'test_entity',
       'bundle' => $this->instance['bundle'],
       'label' => $this->randomName() . '_label',
       'description' => $this->randomName() . '_description',
@@ -489,30 +513,31 @@ function testEntityDeleteBundle() {
     entity_create('field_instance', $instance)->save();
 
     // Save an entity with data for both fields
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
     $values = $this->_generateTestFieldValues($this->field['cardinality']);
-    $entity->{$this->field_name} = $values;
-    $entity->{$field_name} = $this->_generateTestFieldValues(1);
+    $entity->{$this->field_name}[$langcode] = $values;
+    $entity->{$field_name}[$langcode] = $this->_generateTestFieldValues(1);
     field_attach_insert($entity);
 
     // Verify the fields are present on load
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $entity));
-    $this->assertEqual(count($entity->{$this->field_name}), 4, 'First field got loaded');
-    $this->assertEqual(count($entity->{$field_name}), 1, 'Second field got loaded');
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    field_attach_load('test_entity', array(0 => $entity));
+    $this->assertEqual(count($entity->{$this->field_name}[$langcode]), 4, 'First field got loaded');
+    $this->assertEqual(count($entity->{$field_name}[$langcode]), 1, 'Second field got loaded');
 
     // Delete the bundle.
-    entity_test_delete_bundle($this->instance['bundle'], $entity_type);
+    field_test_delete_bundle($this->instance['bundle']);
 
     // Verify no data gets loaded
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0, 'type' => $this->instance['bundle']));
-    field_attach_load($entity_type, array(0 => $entity));
-    $this->assertTrue(empty($entity->{$this->field_name}), 'No data for first field');
-    $this->assertTrue(empty($entity->{$field_name}), 'No data for second field');
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
+    field_attach_load('test_entity', array(0 => $entity));
+    $this->assertFalse(isset($entity->{$this->field_name}[$langcode]), 'No data for first field');
+    $this->assertFalse(isset($entity->{$field_name}[$langcode]), 'No data for second field');
 
     // Verify that the instances are gone
-    $this->assertFalse(field_read_instance('entity_test', $this->field_name, $this->instance['bundle']), "First field is deleted");
-    $this->assertFalse(field_read_instance('entity_test', $field_name, $instance['bundle']), "Second field is deleted");
+    $this->assertFalse(field_read_instance('test_entity', $this->field_name, $this->instance['bundle']), "First field is deleted");
+    $this->assertFalse(field_read_instance('test_entity', $field_name, $instance['bundle']), "Second field is deleted");
   }
 
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php
index 6e4b8b8..523687b 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportChangeTest.php
@@ -32,7 +32,7 @@ public static function getInfo() {
    */
   function testImportChange() {
     $field_id = 'field_test_import';
-    $instance_id = "entity_test.entity_test.$field_id";
+    $instance_id = "test_entity.test_bundle.$field_id";
     $instance_config_name = "field.instance.$instance_id";
 
     // Import default config.
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php
index bdfae09..e8aa4bb 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportCreateTest.php
@@ -27,10 +27,10 @@ public static function getInfo() {
    */
   function testImportCreateDefault() {
     $field_id = 'field_test_import';
-    $instance_id = "entity_test.entity_test.$field_id";
+    $instance_id = "test_entity.test_bundle.$field_id";
     $field_id_2 = 'field_test_import_2';
-    $instance_id_2a = "entity_test.entity_test.$field_id_2";
-    $instance_id_2b = "entity_test.entity_test.$field_id_2";
+    $instance_id_2a = "test_entity.test_bundle.$field_id_2";
+    $instance_id_2b = "test_entity.test_bundle_2.$field_id_2";
 
     // Check that the fields and instances do not exist yet.
     $this->assertFalse(entity_load('field_entity', $field_id));
@@ -40,7 +40,7 @@ function testImportCreateDefault() {
     $this->assertFalse(entity_load('field_instance', $instance_id_2b));
 
     // Create a second bundle for the 'Entity test' entity type.
-    entity_test_create_bundle('test_bundle');
+    entity_test_create_bundle('test_bundle_2');
 
     // Enable field_test_config module and check that the field and instance
     // shipped in the module's default config were created.
@@ -61,12 +61,12 @@ function testImportCreateDefault() {
     $this->assertTrue($instance->bundle, 'test_bundle_2', 'The second field instance was created on bundle test_bundle_2.');
 
     // Tests field info contains the right data.
-    $instances = Field::fieldInfo()->getInstances('entity_test');
-    $this->assertEqual(count($instances['entity_test']), 2);
-    $this->assertTrue(isset($instances['entity_test']['field_test_import']));
-    $this->assertTrue(isset($instances['entity_test']['field_test_import_2']));
-    $this->assertEqual(count($instances['test_bundle']), 1);
+    $instances = Field::fieldInfo()->getInstances('test_entity');
+    $this->assertEqual(count($instances['test_bundle']), 2);
+    $this->assertTrue(isset($instances['test_bundle']['field_test_import']));
     $this->assertTrue(isset($instances['test_bundle']['field_test_import_2']));
+    $this->assertEqual(count($instances['test_bundle_2']), 1);
+    $this->assertTrue(isset($instances['test_bundle_2']['field_test_import_2']));
   }
 
   /**
@@ -75,14 +75,14 @@ function testImportCreateDefault() {
   function testImportCreate() {
     // One field with one field instance.
     $field_id = 'field_test_import_staging';
-    $instance_id = "entity_test.entity_test.$field_id";
+    $instance_id = "test_entity.test_bundle.$field_id";
     $field_config_name = "field.field.$field_id";
     $instance_config_name = "field.instance.$instance_id";
 
     // One field with two field instances.
     $field_id_2 = 'field_test_import_staging_2';
-    $instance_id_2a = "entity_test.test_bundle.$field_id_2";
-    $instance_id_2b = "entity_test.test_bundle_2.$field_id_2";
+    $instance_id_2a = "test_entity.test_bundle.$field_id_2";
+    $instance_id_2b = "test_entity.test_bundle_2.$field_id_2";
     $field_config_name_2 = "field.field.$field_id_2";
     $instance_config_name_2a = "field.instance.$instance_id_2a";
     $instance_config_name_2b = "field.instance.$instance_id_2b";
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php
index 216d36a..73ed136 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldImportDeleteTest.php
@@ -33,9 +33,9 @@ public static function getInfo() {
   public function testImportDelete() {
     $field_id = 'field_test_import';
     $field_id_2 = 'field_test_import_2';
-    $instance_id = "entity_test.test_bundle.$field_id";
-    $instance_id_2a = "entity_test.test_bundle.$field_id_2";
-    $instance_id_2b = "entity_test.test_bundle_2.$field_id_2";
+    $instance_id = "test_entity.test_bundle.$field_id";
+    $instance_id_2a = "test_entity.test_bundle.$field_id_2";
+    $instance_id_2b = "test_entity.test_bundle_2.$field_id_2";
     $field_config_name = "field.field.$field_id";
     $field_config_name_2 = "field.field.$field_id_2";
     $instance_config_name = "field.instance.$instance_id";
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
index 0c3521f..1388168 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInfoTest.php
@@ -46,11 +46,11 @@ function testFieldInfo() {
     }
 
     // Verify that no unexpected instances exist.
-    $instances = field_info_instances('entity_test');
+    $instances = field_info_instances('test_entity');
     $expected = array();
-    $this->assertIdentical($instances, $expected, format_string("field_info_instances('entity_test') returns %expected.", array('%expected' => var_export($expected, TRUE))));
-    $instances = field_info_instances('entity_test', 'entity_test');
-    $this->assertIdentical($instances, array(), "field_info_instances('entity_test', 'entity_test') returns an empty array.");
+    $this->assertIdentical($instances, $expected, format_string("field_info_instances('test_entity') returns %expected.", array('%expected' => var_export($expected, TRUE))));
+    $instances = field_info_instances('test_entity', 'test_bundle');
+    $this->assertIdentical($instances, array(), "field_info_instances('test_entity', 'test_bundle') returns an empty array.");
 
     // Create a field, verify it shows up.
     $core_fields = field_info_fields();
@@ -74,8 +74,8 @@ function testFieldInfo() {
     // Create an instance, verify that it shows up
     $instance_definition = array(
       'field_name' => $field['field_name'],
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
       'label' => $this->randomName(),
       'description' => $this->randomName(),
       'weight' => mt_rand(0, 127),
@@ -83,20 +83,20 @@ function testFieldInfo() {
     $instance = entity_create('field_instance', $instance_definition);
     $instance->save();
 
-    $info = entity_get_info('entity_test');
-    $instances = field_info_instances('entity_test', $instance['bundle']);
+    $info = entity_get_info('test_entity');
+    $instances = field_info_instances('test_entity', $instance['bundle']);
     $this->assertEqual(count($instances), 1, format_string('One instance shows up in info when attached to a bundle on a @label.', array(
       '@label' => $info['label']
     )));
     $this->assertTrue($instance_definition < $instances[$instance['field_name']], 'Instance appears in info correctly');
 
     // Test a valid entity type but an invalid bundle.
-    $instances = field_info_instances('entity_test', 'invalid_bundle');
-    $this->assertIdentical($instances, array(), "field_info_instances('entity_test', 'invalid_bundle') returns an empty array.");
+    $instances = field_info_instances('test_entity', 'invalid_bundle');
+    $this->assertIdentical($instances, array(), "field_info_instances('test_entity', 'invalid_bundle') returns an empty array.");
 
     // Test invalid entity type and bundle.
     $instances = field_info_instances('invalid_entity', $instance['bundle']);
-    $this->assertIdentical($instances, array(), "field_info_instances('invalid_entity', 'entity_test') returns an empty array.");
+    $this->assertIdentical($instances, array(), "field_info_instances('invalid_entity', 'test_bundle') returns an empty array.");
 
     // Test invalid entity type, no bundle provided.
     $instances = field_info_instances('invalid_entity');
@@ -158,8 +158,8 @@ function testInstancePrepare() {
     entity_create('field_entity', $field_definition)->save();
     $instance_definition = array(
       'field_name' => $field_definition['field_name'],
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     );
     $instance = entity_create('field_instance', $instance_definition);
     $instance->save();
@@ -212,8 +212,8 @@ function testFieldMap() {
     // We will overlook fields created by the 'standard' installation profile.
     $exclude = field_info_field_map();
 
-    // Create a new bundle for 'entity_test' entity type.
-    entity_test_create_bundle('test_bundle_2');
+    // Create a new bundle for 'test_entity' entity type.
+    field_test_create_bundle('test_bundle_2');
 
     // Create a couple fields.
     $fields  = array(
@@ -234,23 +234,23 @@ function testFieldMap() {
     $instances = array(
       array(
         'field_name' => 'field_1',
-        'entity_type' => 'entity_test',
-        'bundle' => 'entity_test',
+        'entity_type' => 'test_entity',
+        'bundle' => 'test_bundle',
       ),
       array(
         'field_name' => 'field_1',
-        'entity_type' => 'entity_test',
+        'entity_type' => 'test_entity',
         'bundle' => 'test_bundle_2',
       ),
       array(
         'field_name' => 'field_2',
-        'entity_type' => 'entity_test',
-        'bundle' => 'entity_test',
+        'entity_type' => 'test_entity',
+        'bundle' => 'test_bundle',
       ),
       array(
         'field_name' => 'field_2',
-        'entity_type' => 'entity_test_cache',
-        'bundle' => 'entity_test',
+        'entity_type' => 'test_cacheable_entity',
+        'bundle' => 'test_bundle',
       ),
     );
     foreach ($instances as $instance) {
@@ -261,14 +261,14 @@ function testFieldMap() {
       'field_1' => array(
         'type' => 'test_field',
         'bundles' => array(
-          'entity_test' => array('entity_test', 'test_bundle_2'),
+          'test_entity' => array('test_bundle', 'test_bundle_2'),
         ),
       ),
       'field_2' => array(
         'type' => 'hidden_test_field',
         'bundles' => array(
-          'entity_test' => array('entity_test'),
-          'entity_test_cache' => array('entity_test'),
+          'test_entity' => array('test_bundle'),
+          'test_cacheable_entity' => array('test_bundle'),
         ),
       ),
     );
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
index 29e6cb2..9caf203 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldInstanceCrudTest.php
@@ -51,8 +51,8 @@ function setUp() {
     $this->field->save();
     $this->instance_definition = array(
       'field_name' => $this->field['field_name'],
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     );
   }
 
@@ -107,7 +107,7 @@ function testCreateFieldInstance() {
     $field_restricted_definition = array(
       'field_name' => drupal_strtolower($this->randomName()),
       'type' => 'test_field',
-      'entity_types' => array('entity_test_cache'),
+      'entity_types' => array('test_cacheable_entity'),
     );
     $field_restricted = entity_create('field_entity', $field_restricted_definition);
     $field_restricted->save();
@@ -117,7 +117,7 @@ function testCreateFieldInstance() {
     try {
       $instance = $this->instance_definition;
       $instance['field_name'] = $field_restricted_definition['field_name'];
-      $instance['entity_type'] = 'entity_test_cache';
+      $instance['entity_type'] = 'test_cacheable_entity';
       entity_create('field_instance', $instance)->save();
       $this->pass(t('Can create an instance on an entity type allowed by the field.'));
     }
@@ -147,7 +147,7 @@ function testReadFieldInstance() {
     entity_create('field_instance', $this->instance_definition)->save();
 
     // Read the instance back.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue($this->instance_definition['field_name'] == $instance['field_name'], 'The field was properly read.');
     $this->assertTrue($this->instance_definition['entity_type'] == $instance['entity_type'], 'The field was properly read.');
     $this->assertTrue($this->instance_definition['bundle'] == $instance['bundle'], 'The field was properly read.');
@@ -160,14 +160,14 @@ function testUpdateFieldInstance() {
     entity_create('field_instance', $this->instance_definition)->save();
 
     // Check that basic changes are saved.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $instance['required'] = !$instance['required'];
     $instance['label'] = $this->randomName();
     $instance['description'] = $this->randomName();
     $instance['settings']['test_instance_setting'] = $this->randomName();
     $instance->save();
 
-    $instance_new = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance_new = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertEqual($instance['required'], $instance_new['required'], '"required" change is saved');
     $this->assertEqual($instance['label'], $instance_new['label'], '"label" change is saved');
     $this->assertEqual($instance['description'], $instance_new['description'], '"description" change is saved');
@@ -191,21 +191,21 @@ function testDeleteFieldInstance() {
     entity_create('field_instance', $another_instance_definition)->save();
 
     // Test that the first instance is not deleted, and then delete it.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($instance) && empty($instance['deleted']), 'A new field instance is not marked for deletion.');
     $instance->delete();
 
     // Make sure the instance is marked as deleted when the instance is
     // specifically loaded.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle'], array('include_deleted' => TRUE));
     $this->assertTrue(!empty($instance['deleted']), 'A deleted field instance is marked for deletion.');
 
     // Try to load the instance normally and make sure it does not show up.
-    $instance = field_read_instance('entity_test', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
+    $instance = field_read_instance('test_entity', $this->instance_definition['field_name'], $this->instance_definition['bundle']);
     $this->assertTrue(empty($instance), 'A deleted field instance is not loaded by default.');
 
     // Make sure the other field instance is not deleted.
-    $another_instance = field_read_instance('entity_test', $another_instance_definition['field_name'], $another_instance_definition['bundle']);
+    $another_instance = field_read_instance('test_entity', $another_instance_definition['field_name'], $another_instance_definition['bundle']);
     $this->assertTrue(!empty($another_instance) && empty($another_instance['deleted']), 'A non-deleted field instance is not marked for deletion.');
 
     // Make sure the field is deleted when its last instance is deleted.
diff --git a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
index 4580e7b..4a336ac 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FieldUnitTestBase.php
@@ -36,6 +36,7 @@ function setUp() {
     parent::setUp();
     $this->installSchema('system', array('sequences', 'variable', 'config_snapshot'));
     $this->installSchema('entity_test', 'entity_test');
+    $this->installSchema('field_test', array('test_entity', 'test_entity_revision', 'test_entity_bundle'));
 
     // Set default storage backend and configure the theme system.
     $this->installConfig(array('field', 'system'));
@@ -49,15 +50,12 @@ function setUp() {
    *   PHP variable names as well.
    * @param string $entity_type
    *   (optional) The entity type on which the instance should be created.
-   *   Defaults to "entity_test".
+   *   Defaults to 'test_entity'.
    * @param string $bundle
    *   (optional) The entity type on which the instance should be created.
-   *   Defaults to the default bundle of the entity type.
+   *   Defaults to 'test_bundle'.
    */
-  function createFieldWithInstance($suffix = '', $entity_type = 'entity_test', $bundle = NULL) {
-    if (empty($bundle)) {
-      $bundle = $entity_type;
-    }
+  function createFieldWithInstance($suffix = '', $entity_type = 'test_entity', $bundle = 'test_bundle') {
     $field_name = 'field_name' . $suffix;
     $field = 'field' . $suffix;
     $field_id = 'field_id' . $suffix;
@@ -81,7 +79,7 @@ function createFieldWithInstance($suffix = '', $entity_type = 'entity_test', $bu
     $this->$instance = entity_create('field_instance', $this->$instance_definition);
     $this->$instance->save();
 
-    entity_get_form_display($entity_type, $bundle, 'default')
+    entity_get_form_display('test_entity', 'test_bundle', 'default')
       ->setComponent($this->$field_name, array(
         'type' => 'test_field_widget',
         'settings' => array(
@@ -126,7 +124,7 @@ function _generateTestFieldValues($cardinality) {
    */
   function assertFieldValues(EntityInterface $entity, $field_name, $langcode, $expected_values, $column = 'value') {
     $e = clone $entity;
-    field_attach_load('entity_test', array($e->id() => $e));
+    field_attach_load('test_entity', array($e->ftid => $e));
     $values = isset($e->{$field_name}[$langcode]) ? $e->{$field_name}[$langcode] : array();
     $this->assertEqual(count($values), count($expected_values), 'Expected number of values were saved.');
     foreach ($expected_values as $key => $value) {
diff --git a/core/modules/field/lib/Drupal/field/Tests/FormTest.php b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
index b7c600e..97fb33b 100644
--- a/core/modules/field/lib/Drupal/field/Tests/FormTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/FormTest.php
@@ -17,7 +17,7 @@ class FormTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('node', 'field_test', 'options', 'entity_test');
+  public static $modules = array('node', 'field_test', 'options');
 
   /**
    * An array of values defining a field single.
@@ -58,7 +58,7 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
+    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
     $this->drupalLogin($web_user);
 
     $this->field_single = array('field_name' => 'field_single', 'type' => 'test_field');
@@ -66,8 +66,8 @@ function setUp() {
     $this->field_unlimited = array('field_name' => 'field_unlimited', 'type' => 'test_field', 'cardinality' => FIELD_CARDINALITY_UNLIMITED);
 
     $this->instance = array(
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
       'label' => $this->randomName() . '_label',
       'description' => '[site:name]_description',
       'weight' => mt_rand(0, 127),
@@ -89,7 +89,7 @@ function testFieldFormSingle() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('entity_test/add');
+    $this->drupalGet('test-entity/add/test_bundle');
 
     // Create token value expected for description.
     $token_description = check_plain(config('system.site')->get('name')) . '_description';
@@ -102,59 +102,43 @@ function testFieldFormSingle() {
     $this->assertNoText('From hook_field_widget_form_alter(): Default form is true.', 'Not default value form in hook_field_widget_form_alter().');
 
     // Submit with invalid value (field-level validation).
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => -1
-    );
+    $edit = array("{$field_name}[$langcode][0][value]" => -1);
     $this->drupalPost(NULL, $edit, t('Save'));
     $this->assertRaw(t('%name does not accept the value -1.', array('%name' => $this->instance['label'])), 'Field validation fails with invalid input.');
     // TODO : check that the correct field is flagged for error.
 
     // Create an entity
     $value = mt_rand(1, 127);
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => $value,
-    );
+    $edit = array("{$field_name}[$langcode][0][value]" => $value);
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = entity_load('entity_test', $id);
-    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $value, 'Field value was saved');
 
     // Display edit form.
-    $this->drupalGet('entity_test/manage/' . $id . '/edit');
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
     $this->assertFieldByName("{$field_name}[$langcode][0][value]", $value, 'Widget is displayed with the correct default value');
     $this->assertNoField("{$field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
 
     // Update the entity.
     $value = mt_rand(1, 127);
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => $value,
-    );
+    $edit = array("{$field_name}[$langcode][0][value]" => $value);
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText(t('entity_test @id has been updated.', array('@id' => $id)), 'Entity was updated');
-    $this->container->get('plugin.manager.entity')->getStorageController('entity_test')->resetCache(array($id));
-    $entity = entity_load('entity_test', $id);
-    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
+    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $value, 'Field value was updated');
 
     // Empty the field.
     $value = '';
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => $value
-    );
-    $this->drupalPost('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
-    $this->assertText(t('entity_test @id has been updated.', array('@id' => $id)), 'Entity was updated');
-    $this->container->get('plugin.manager.entity')->getStorageController('entity_test')->resetCache(array($id));
-    $entity = entity_load('entity_test', $id);
-    $this->assertTrue($entity->{$field_name}->isEmpty(), 'Field was emptied');
+    $edit = array("{$field_name}[$langcode][0][value]" => $value);
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
+    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertIdentical($entity->{$field_name}, array(), 'Field was emptied');
   }
 
   /**
@@ -174,22 +158,18 @@ function testFieldFormDefaultValue() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('entity_test/add');
+    $this->drupalGet('test-entity/add/test_bundle');
     // Test that the default value is displayed correctly.
     $this->assertFieldByXpath("//input[@name='{$field_name}[$langcode][0][value]' and @value='$default']");
 
     // Try to submit an empty value.
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => '',
-    );
+    $edit = array("{$field_name}[$langcode][0][value]" => '');
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created.');
-    $entity = entity_load('entity_test', $id);
-    $this->assertTrue($entity->{$field_name}->isEmpty(), 'Field is now empty.');
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created.');
+    $entity = field_test_entity_test_load($id);
+    $this->assertTrue(empty($entity->{$field_name}), 'Field is now empty.');
   }
 
   function testFieldFormSingleRequired() {
@@ -206,31 +186,23 @@ function testFieldFormSingleRequired() {
 
     // Submit with missing required value.
     $edit = array();
-    $this->drupalPost('entity_test/add', $edit, t('Save'));
+    $this->drupalPost('test-entity/add/test_bundle', $edit, t('Save'));
     $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
 
     // Create an entity
     $value = mt_rand(1, 127);
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => $value,
-    );
+    $edit = array("{$field_name}[$langcode][0][value]" => $value);
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = entity_load('entity_test', $id);
-    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was saved');
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $value, 'Field value was saved');
 
     // Edit with missing required value.
     $value = '';
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => $value,
-    );
-    $this->drupalPost('entity_test/manage/' . $id . '/edit', $edit, t('Save'));
+    $edit = array("{$field_name}[$langcode][0][value]" => $value);
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
     $this->assertRaw(t('!name field is required.', array('!name' => $this->instance['label'])), 'Required field with no value fails validation');
   }
 
@@ -254,7 +226,7 @@ function testFieldFormUnlimited() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Display creation form -> 1 widget.
-    $this->drupalGet('entity_test/add');
+    $this->drupalGet('test-entity/add/test_bundle');
     $this->assertFieldByName("{$field_name}[$langcode][0][value]", '', 'Widget 1 is displayed');
     $this->assertNoField("{$field_name}[$langcode][1][value]", 'No extraneous widget is displayed');
 
@@ -271,11 +243,7 @@ function testFieldFormUnlimited() {
     // Prepare values and weights.
     $count = 3;
     $delta_range = $count - 1;
-    $values = $weights = $pattern = $expected_values = array();
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-    );
+    $values = $weights = $pattern = $expected_values = $edit = array();
     for ($delta = 0; $delta <= $delta_range; $delta++) {
       // Assign unique random values and weights.
       do {
@@ -308,13 +276,13 @@ function testFieldFormUnlimited() {
 
     // Submit the form and create the entity.
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertText(t('entity_test @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = entity_load('entity_test', $id);
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = field_test_entity_test_load($id);
     ksort($field_values);
     $field_values = array_values($field_values);
-    $this->assertIdentical($entity->{$field_name}->getValue(), $field_values, 'Field values were saved in the correct order');
+    $this->assertIdentical($entity->{$field_name}[$langcode], $field_values, 'Field values were saved in the correct order');
 
     // Display edit form: check that the expected number of widgets is
     // displayed, with correct values change values, reorder, leave an empty
@@ -350,8 +318,8 @@ function testFieldFormMultivalueWithRequiredRadio() {
     ))->save();
     $instance = array(
       'field_name' => 'required_radio_test',
-      'entity_type' => 'entity_test',
-      'bundle' => 'entity_test',
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
       'required' => TRUE,
     );
     entity_create('field_instance', $instance)->save();
@@ -362,7 +330,7 @@ function testFieldFormMultivalueWithRequiredRadio() {
       ->save();
 
     // Display creation form.
-    $this->drupalGet('entity_test/add');
+    $this->drupalGet('test-entity/add/test_bundle');
 
     // Press the 'Add more' button.
     $this->drupalPost(NULL, array(), t('Add another item'));
@@ -388,7 +356,7 @@ function testFieldFormJSAddMore() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Display creation form -> 1 widget.
-    $this->drupalGet('entity_test/add');
+    $this->drupalGet('test-entity/add/test_bundle');
 
     // Press 'add more' button a couple times -> 3 widgets.
     // drupalPostAJAX() will not work iteratively, so we add those through
@@ -452,25 +420,21 @@ function testFieldFormMultipleWidget() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Display creation form.
-    $this->drupalGet('entity_test/add');
+    $this->drupalGet('test-entity/add/test_bundle');
     $this->assertFieldByName("{$field_name}[$langcode]", '', 'Widget is displayed.');
 
     // Create entity with three values.
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode]" => '1, 2, 3',
-    );
+    $edit = array("{$field_name}[$langcode]" => '1, 2, 3');
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match('|entity_test/manage/(\d+)/edit|', $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
 
     // Check that the values were saved.
-    $entity_init = entity_load('entity_test', $id);
+    $entity_init = field_test_create_entity($id);
     $this->assertFieldValues($entity_init, $field_name, $langcode, array(1, 2, 3));
 
     // Display the form, check that the values are correctly filled in.
-    $this->drupalGet('entity_test/manage/' . $id . '/edit');
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
     $this->assertFieldByName("{$field_name}[$langcode]", '1, 2, 3', 'Widget is displayed.');
 
     // Submit the form with more values than the field accepts.
@@ -488,14 +452,11 @@ function testFieldFormAccess() {
     // Create a "regular" field.
     $field = $this->field_single;
     $field_name = $field['field_name'];
-    $entity_type = 'entity_test_rev';
     $instance = $this->instance;
     $instance['field_name'] = $field_name;
-    $instance['entity_type'] = $entity_type;
-    $instance['bundle'] = $entity_type;
     entity_create('field_entity', $field)->save();
     entity_create('field_instance', $instance)->save();
-    entity_get_form_display($entity_type, $entity_type, 'default')
+    entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
       ->setComponent($field_name)
       ->save();
 
@@ -507,8 +468,8 @@ function testFieldFormAccess() {
     $field_name_no_access = $field_no_access['field_name'];
     $instance_no_access = array(
       'field_name' => $field_name_no_access,
-      'entity_type' => $entity_type,
-      'bundle' => $entity_type,
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
       'default_value' => array(0 => array('value' => 99)),
     );
     entity_create('field_entity', $field_no_access)->save();
@@ -521,67 +482,56 @@ function testFieldFormAccess() {
 
     // Test that the form structure includes full information for each delta
     // apart from #access.
-    $entity = entity_create($entity_type, array('id' => 0, 'revision_id' => 0));
+    $entity_type = 'test_entity';
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
 
     $form = array();
     $form_state = form_state_defaults();
-    $form_state['form_display'] = entity_get_form_display($entity_type, $entity_type, 'default');
+    $form_state['form_display'] = entity_get_form_display($entity_type, $this->instance['bundle'], 'default');
     field_attach_form($entity, $form, $form_state);
 
     $this->assertEqual($form[$field_name_no_access][$langcode][0]['value']['#entity_type'], $entity_type, 'The correct entity type is set in the field structure.');
     $this->assertFalse($form[$field_name_no_access]['#access'], 'Field #access is FALSE for the field without edit access.');
 
     // Display creation form.
-    $this->drupalGet($entity_type . '/add');
+    $this->drupalGet('test-entity/add/test_bundle');
     $this->assertNoFieldByName("{$field_name_no_access}[$langcode][0][value]", '', 'Widget is not displayed if field access is denied.');
 
     // Create entity.
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => 1,
-    );
+    $edit = array("{$field_name}[$langcode][0][value]" => 1);
     $this->drupalPost(NULL, $edit, t('Save'));
-    preg_match("|$entity_type/manage/(\d+)/edit|", $this->url, $match);
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
 
     // Check that the default value was saved.
-    $entity = entity_load($entity_type, $id);
-    $this->assertEqual($entity->$field_name_no_access->value, 99, 'Default value was saved for the field with no edit access.');
-    $this->assertEqual($entity->$field_name->value, 1, 'Entered value vas saved for the field with edit access.');
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, 'Default value was saved for the field with no edit access.');
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 1, 'Entered value vas saved for the field with edit access.');
 
     // Create a new revision.
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => 2,
-      'revision' => TRUE,
-    );
-    $this->drupalPost($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
+    $edit = array("{$field_name}[$langcode][0][value]" => 2, 'revision' => TRUE);
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
 
     // Check that the new revision has the expected values.
-    $this->container->get('plugin.manager.entity')->getStorageController($entity_type)->resetCache(array($id));
-    $entity = entity_load($entity_type, $id);
-    $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
-    $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
+    $this->container->get('plugin.manager.entity')->getStorageController('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, 'New revision has the expected value for the field with no edit access.');
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, 'New revision has the expected value for the field with edit access.');
 
     // Check that the revision is also saved in the revisions table.
-//    $entity = entity_revision_load($entity_type, $entity->getRevisionId());
-    $this->assertEqual($entity->$field_name_no_access->value, 99, 'New revision has the expected value for the field with no edit access.');
-    $this->assertEqual($entity->$field_name->value, 2, 'New revision has the expected value for the field with edit access.');
+    $entity = field_test_entity_test_load($id, $entity->ftvid);
+    $this->assertEqual($entity->{$field_name_no_access}[$langcode][0]['value'], 99, 'New revision has the expected value for the field with no edit access.');
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 2, 'New revision has the expected value for the field with edit access.');
   }
 
   /**
    * Tests the Hidden widget.
    */
   function testFieldFormHiddenWidget() {
-    $entity_type = 'entity_test_rev';
     $field = $this->field_single;
     $field_name = $field['field_name'];
     $this->instance['field_name'] = $field_name;
     $this->instance['default_value'] = array(0 => array('value' => 99));
-    $this->instance['entity_type'] = $entity_type;
-    $this->instance['bundle'] = $entity_type;
     entity_create('field_entity', $field)->save();
     $this->instance = entity_create('field_instance', $this->instance);
     $this->instance->save();
@@ -593,17 +543,17 @@ function testFieldFormHiddenWidget() {
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Display the entity creation form.
-    $this->drupalGet($entity_type . '/add');
+    $this->drupalGet('test-entity/add/test_bundle');
 
     // Create an entity and test that the default value is assigned correctly to
     // the field that uses the hidden widget.
     $this->assertNoField("{$field_name}[$langcode][0][value]", 'The hidden widget is not displayed');
-    $this->drupalPost(NULL, array('user_id' => 1, 'name' => $this->randomName()), t('Save'));
-    preg_match('|' . $entity_type . '/manage/(\d+)/edit|', $this->url, $match);
+    $this->drupalPost(NULL, array(), t('Save'));
+    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
     $id = $match[1];
-    $this->assertText(t('entity_test_rev @id has been created.', array('@id' => $id)), 'Entity was created');
-    $entity = entity_load($entity_type, $id);
-    $this->assertEqual($entity->{$field_name}->value, 99, 'Default value was saved');
+    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), 'Entity was created');
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], 99, 'Default value was saved');
 
     // Update the instance to remove the default value and switch to the
     // default widget.
@@ -616,17 +566,17 @@ function testFieldFormHiddenWidget() {
       ->save();
 
     // Display edit form.
-    $this->drupalGet($entity_type . '/manage/' . $id . '/edit');
+    $this->drupalGet('test-entity/manage/' . $id . '/edit');
     $this->assertFieldByName("{$field_name}[$langcode][0][value]", 99, 'Widget is displayed with the correct default value');
 
     // Update the entity.
     $value = mt_rand(1, 127);
     $edit = array("{$field_name}[$langcode][0][value]" => $value);
     $this->drupalPost(NULL, $edit, t('Save'));
-    $this->assertText(t('entity_test_rev @id has been updated.', array('@id' => $id)), 'Entity was updated');
-    entity_get_controller($entity_type)->resetCache(array($id));
-    $entity = entity_load($entity_type, $id);
-    $this->assertEqual($entity->{$field_name}->value, $value, 'Field value was updated');
+    $this->assertRaw(t('test_entity @id has been updated.', array('@id' => $id)), 'Entity was updated');
+    entity_get_controller('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $value, 'Field value was updated');
 
     // Update the form display and switch to the Hidden widget again.
     entity_get_form_display($this->instance['entity_type'], $this->instance['bundle'], 'default')
@@ -637,12 +587,29 @@ function testFieldFormHiddenWidget() {
 
     // Create a new revision.
     $edit = array('revision' => TRUE);
-    $this->drupalPost($entity_type . '/manage/' . $id . '/edit', $edit, t('Save'));
+    $this->drupalPost('test-entity/manage/' . $id . '/edit', $edit, t('Save'));
 
     // Check that the expected value has been carried over to the new revision.
-    entity_get_controller($entity_type)->resetCache(array($id));
-    $entity = entity_load($entity_type, $id);
-    $this->assertEqual($entity->{$field_name}->value, $value, 'New revision has the expected value for the field with the Hidden widget');
+    entity_get_controller('test_entity')->resetCache(array($id));
+    $entity = field_test_entity_test_load($id);
+    $this->assertEqual($entity->{$field_name}[$langcode][0]['value'], $value, 'New revision has the expected value for the field with the Hidden widget');
+  }
+
+  /**
+   * {inheritdoc}
+   */
+  function assertFieldValues(EntityInterface $entity, $field_name, $langcode, $expected_values, $column = 'value') {
+    // Override the base implementation with one that works with the old
+    // entity API.
+    // @todo: Remove this when replacing the remaining of test_entity with
+    //   entity_test.
+    $e = clone $entity;
+    field_attach_load('test_entity', array($e->ftid => $e));
+    $values = isset($e->{$field_name}[$langcode]) ? $e->{$field_name}[$langcode] : array();
+    $this->assertEqual(count($values), count($expected_values), 'Expected number of values were saved.');
+    foreach ($expected_values as $key => $value) {
+      $this->assertEqual($values[$key][$column], $value, format_string('Value @value was saved correctly.', array('@value' => $value)));
+    }
   }
 
 }
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
index 91a33d0..8562a07 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationTest.php
@@ -80,11 +80,10 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
     $this->installSchema('language', array('language'));
+    $this->installSchema('node', array('node_type'));
 
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
 
-    $this->entity_type = 'entity_test';
-
     $this->field_definition = array(
       'field_name' => $this->field_name,
       'type' => 'test_field',
@@ -97,10 +96,10 @@ function setUp() {
     $this->instance_definition = array(
       'field_name' => $this->field_name,
       'entity_type' => $this->entity_type,
-      'bundle' => 'entity_test',
+      'bundle' => 'test_bundle',
     );
     entity_create('field_instance', $this->instance_definition)->save();
-    $this->instance = field_read_instance($this->entity_type, $this->field_name, $this->entity_type);
+    $this->instance = field_read_instance('test_entity', $this->field_name, 'test_bundle');
 
     for ($i = 0; $i < 3; ++$i) {
       $language = new Language(array(
@@ -116,12 +115,12 @@ function setUp() {
    */
   function testFieldAvailableLanguages() {
     // Test 'translatable' fieldable info.
-    field_test_entity_info_translatable('entity_test', FALSE);
+    field_test_entity_info_translatable('test_entity', FALSE);
     $field = clone($this->field);
     $field['field_name'] .= '_untranslatable';
 
     // Enable field translations for the entity.
-    field_test_entity_info_translatable('entity_test', TRUE);
+    field_test_entity_info_translatable('test_entity', TRUE);
 
     // Test hook_field_languages() invocation on a translatable field.
     \Drupal::state()->set('field_test.field_available_languages_alter', TRUE);
@@ -152,30 +151,28 @@ function testTranslatableFieldSaveLoad() {
     $this->assertTrue(count($entity_info['translatable']), 'Nodes are translatable.');
 
     // Prepare the field translations.
-    $entity_type = 'entity_test';
-    field_test_entity_info_translatable($entity_type, TRUE);
-    $id = $revision_id = 1;
-    $entity = entity_create($entity_type, array('id' => $id, 'revision_id' => $revision_id, 'type' => $this->instance['bundle']));
+    field_test_entity_info_translatable('test_entity', TRUE);
+    $eid = $evid = 1;
+    $entity_type = 'test_entity';
+    $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
     $field_translations = array();
     $available_langcodes = field_available_languages($entity_type, $this->field);
     $this->assertTrue(count($available_langcodes) > 1, 'Field is translatable.');
-    $entity->langcode->value = reset($available_langcodes);
     foreach ($available_langcodes as $langcode) {
       $field_translations[$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
-      $entity->getTranslation($langcode)->{$this->field_name}->setValue($field_translations[$langcode]);
     }
 
     // Save and reload the field translations.
+    $entity->{$this->field_name} = $field_translations;
     field_attach_insert($entity);
-    $entity = entity_create($entity_type, array('id' => $id, 'revision_id' => $revision_id, 'type' => $this->instance['bundle']));
-    $entity->langcode->value = reset($available_langcodes);
-    field_attach_load($entity_type, array($id => $entity));
+    unset($entity->{$this->field_name});
+    field_attach_load($entity_type, array($eid => $entity));
 
     // Check if the correct values were saved/loaded.
     foreach ($field_translations as $langcode => $items) {
       $result = TRUE;
       foreach ($items as $delta => $item) {
-        $result = $result && $item['value'] == $entity->getTranslation($langcode)->{$this->field_name}[$delta]->value;
+        $result = $result && $item['value'] == $entity->{$this->field_name}[$langcode][$delta]['value'];
       }
       $this->assertTrue($result, format_string('%language translation correctly handled.', array('%language' => $langcode)));
     }
@@ -192,45 +189,39 @@ function testTranslatableFieldSaveLoad() {
     $instance = entity_create('field_instance', $instance_definition);
     $instance->save();
 
-    entity_info_cache_clear();
-
     $translation_langcodes = array_slice($available_langcodes, 0, 2);
     asort($translation_langcodes);
     $translation_langcodes = array_values($translation_langcodes);
 
-    $id++;
-    $revision_id++;
-    $values = array('id' => $id, 'revision_id' => $revision_id, 'type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
-    $entity = entity_create($entity_type, $values);
+    $eid++;
+    $evid++;
+    $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
     foreach ($translation_langcodes as $langcode) {
       $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
-      $entity->getTranslation($langcode, FALSE)->{$this->field_name}->setValue($values[$this->field_name][$langcode]);
     }
+    $entity = entity_create($entity_type, $values);
 
-    $field_langcodes = array_keys($entity->getTranslationLanguages());
-    sort($field_langcodes);
+    ksort($entity->{$field_name_default});
+    $field_langcodes = array_keys($entity->{$field_name_default});
     $this->assertEqual($translation_langcodes, $field_langcodes, 'Missing translations did not get a default value.');
 
-    // @todo Test every translation once the Entity Translation API allows for
-    //   multilingual defaults.
-    $langcode = $entity->language()->langcode;
-    $this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $instance['default_value'], format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
+    foreach ($entity->{$field_name_default} as $langcode => $items) {
+      $this->assertEqual($items, $instance['default_value'], format_string('Default value correctly populated for language %language.', array('%language' => $langcode)));
+    }
 
     // Check that explicit empty values are not overridden with default values.
     foreach (array(NULL, array()) as $empty_items) {
-      $id++;
-      $revision_id++;
-      $values = array('id' => $id, 'revision_id' => $revision_id, 'type' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
-      $entity = entity_create($entity_type, $values);
+      $eid++;
+      $evid++;
+      $values = array('eid' => $eid, 'evid' => $evid, 'fttype' => $instance['bundle'], 'langcode' => $translation_langcodes[0]);
       foreach ($translation_langcodes as $langcode) {
         $values[$this->field_name][$langcode] = $this->_generateTestFieldValues($this->field['cardinality']);
-        $entity->getTranslation($langcode)->{$this->field_name}->setValue($values[$this->field_name][$langcode]);
-        $entity->getTranslation($langcode)->{$field_name_default}->setValue($empty_items);
         $values[$field_name_default][$langcode] = $empty_items;
       }
+      $entity = entity_create($entity_type, $values);
 
-      foreach ($entity->getTranslationLanguages() as $langcode => $language) {
-        $this->assertEqual($entity->getTranslation($langcode)->{$field_name_default}->getValue(), $empty_items, format_string('Empty value correctly populated for language %language.', array('%language' => $langcode)));
+      foreach ($entity->{$field_name_default} as $langcode => $items) {
+        $this->assertEqual($items, $empty_items, format_string('Empty value correctly populated for language %language.', array('%language' => $langcode)));
       }
     }
   }
@@ -240,7 +231,7 @@ function testTranslatableFieldSaveLoad() {
    */
   function testFieldDisplayLanguage() {
     $field_name = drupal_strtolower($this->randomName() . '_field_name');
-    $entity_type = 'entity_test';
+    $entity_type = 'test_entity';
 
     // We need an additional field here to properly test display language
     // suggestions.
@@ -255,15 +246,14 @@ function testFieldDisplayLanguage() {
     $instance = array(
       'field_name' => $field['field_name'],
       'entity_type' => $entity_type,
-      'bundle' => 'entity_test',
+      'bundle' => 'test_bundle',
     );
     entity_create('field_instance', $instance)->save();
 
-    $enabled_langcodes = field_content_languages();
-    $entity = entity_create($entity_type, array('id' => 1, 'revision_id' => 1, 'type' => $this->instance['bundle']));;
-    $entity->langcode->value = reset($enabled_langcodes);
+    $entity = field_test_create_entity(1, 1, $this->instance['bundle']);
     $instances = field_info_instances($entity_type, $this->instance['bundle']);
 
+    $enabled_langcodes = field_content_languages();
     $langcodes = array();
     // This array is used to store, for each field name, which one of the locked
     // languages will be used for display.
@@ -281,7 +271,7 @@ function testFieldDisplayLanguage() {
       }
       while (isset($langcodes[$langcode]));
       $langcodes[$langcode] = TRUE;
-      $entity->getTranslation($langcode)->{$field_name}->setValue($this->_generateTestFieldValues($field['cardinality']));
+      $entity->{$field_name}[$langcode] = $this->_generateTestFieldValues($field['cardinality']);
       // If the langcode is one of the locked languages, then that one
       // will also be used for display. Otherwise, the default one should be
       // used, which is Language::LANGCODE_NOT_SPECIFIED.
@@ -313,19 +303,19 @@ function testFieldDisplayLanguage() {
       // As the requested language was not assinged to any field, if the
       // returned language is defined for the current field, core fallback rules
       // were successfully applied.
-      $this->assertTrue(!empty($entity->getTranslation($langcode)->{$field_name}) && $langcode != $requested_langcode, format_string('The display language for the field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
+      $this->assertTrue(isset($entity->{$field_name}[$langcode]) && $langcode != $requested_langcode, format_string('The display language for the field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
     }
 
     // Test single-field display language.
     drupal_static_reset('field_language');
     $langcode = field_language($entity, $this->field_name, $requested_langcode);
-    $this->assertTrue(!empty($entity->getTranslation($langcode)->{$this->field_name}) && $langcode != $requested_langcode, format_string('The display language for the (single) field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
+    $this->assertTrue(isset($entity->{$this->field_name}[$langcode]) && $langcode != $requested_langcode, format_string('The display language for the (single) field %field_name is %language.', array('%field_name' => $field_name, '%language' => $langcode)));
 
     // Test field_language() basic behavior without language fallback.
     \Drupal::state()->set('field_test.language_fallback', FALSE);
-    $entity->getTranslation($requested_langcode)->{$this->field_name}->value = mt_rand(1, 127);
+    $entity->{$this->field_name}[$requested_langcode] = mt_rand(1, 127);
     drupal_static_reset('field_language');
-    $display_langcode = field_language($entity->getBCEntity(), $this->field_name, $requested_langcode);
+    $display_langcode = field_language($entity, $this->field_name, $requested_langcode);
     $this->assertEqual($display_langcode, $requested_langcode, 'Display language behave correctly when language fallback is disabled');
   }
 
diff --git a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
index 0893f43..7001ad0 100644
--- a/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
+++ b/core/modules/field/lib/Drupal/field/Tests/TranslationWebTest.php
@@ -19,7 +19,7 @@ class TranslationWebTest extends FieldTestBase {
    *
    * @var array
    */
-  public static $modules = array('language', 'field_test', 'entity_test');
+  public static $modules = array('language', 'field_test');
 
   /**
    * The name of the field to use in this test.
@@ -62,8 +62,6 @@ function setUp() {
 
     $this->field_name = drupal_strtolower($this->randomName() . '_field_name');
 
-    $this->entity_type = 'entity_test_rev';
-
     $field = array(
       'field_name' => $this->field_name,
       'type' => 'test_field',
@@ -76,12 +74,12 @@ function setUp() {
     $instance = array(
       'field_name' => $this->field_name,
       'entity_type' => $this->entity_type,
-      'bundle' => $this->entity_type,
+      'bundle' => 'test_bundle',
     );
     entity_create('field_instance', $instance)->save();
-    $this->instance = field_read_instance($this->entity_type, $this->field_name, $this->entity_type);
+    $this->instance = field_read_instance('test_entity', $this->field_name, 'test_bundle');
 
-    entity_get_form_display($this->entity_type, $this->entity_type, 'default')
+    entity_get_form_display($this->entity_type, 'test_bundle', 'default')
       ->setComponent($this->field_name)
       ->save();
 
@@ -98,48 +96,44 @@ function setUp() {
    * Tests field translations when creating a new revision.
    */
   function testFieldFormTranslationRevisions() {
-    $web_user = $this->drupalCreateUser(array('view test entity', 'administer entity_test content'));
+    $web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content'));
     $this->drupalLogin($web_user);
 
     // Prepare the field translations.
     field_test_entity_info_translatable($this->entity_type, TRUE);
-    $entity = entity_create($this->entity_type, array());
+    $eid = 1;
+    $entity = field_test_create_entity($eid, $eid, $this->instance['bundle']);
     $available_langcodes = array_flip(field_available_languages($this->entity_type, $this->field));
     unset($available_langcodes[Language::LANGCODE_NOT_SPECIFIED]);
     $field_name = $this->field['field_name'];
 
     // Store the field translations.
-    $entity->langcode->value = key($available_langcodes);
+    $entity->enforceIsNew();
     foreach ($available_langcodes as $langcode => $value) {
-      $entity->getTranslation($langcode)->{$field_name}->value = $value + 1;
+      $entity->{$field_name}[$langcode][0]['value'] = $value + 1;
     }
-    $entity->save();
+    field_test_entity_save($entity);
 
     // Create a new revision.
     $langcode = field_valid_language(NULL);
-    $edit = array(
-      'user_id' => 1,
-      'name' => $this->randomName(),
-      "{$field_name}[$langcode][0][value]" => $entity->getTranslation($langcode)->{$field_name}->value,
-      'revision' => TRUE,
-    );
-    $this->drupalPost($this->entity_type . '/manage/' . $entity->id() . '/edit', $edit, t('Save'));
+    $edit = array("{$field_name}[$langcode][0][value]" => $entity->{$field_name}[$langcode][0]['value'], 'revision' => TRUE);
+    $this->drupalPost('test-entity/manage/' . $eid . '/edit', $edit, t('Save'));
 
     // Check translation revisions.
-    $this->checkTranslationRevisions($entity->id(), $entity->getRevisionId(), $available_langcodes);
-    $this->checkTranslationRevisions($entity->id(), $entity->getRevisionId() + 1, $available_langcodes);
+    $this->checkTranslationRevisions($eid, $eid, $available_langcodes);
+    $this->checkTranslationRevisions($eid, $eid + 1, $available_langcodes);
   }
 
   /**
    * Check if the field translation attached to the entity revision identified
    * by the passed arguments were correctly stored.
    */
-  private function checkTranslationRevisions($id, $revision_id, $available_langcodes) {
+  private function checkTranslationRevisions($eid, $evid, $available_langcodes) {
     $field_name = $this->field['field_name'];
-    $entity = entity_revision_load($this->entity_type, $revision_id);
+    $entity = field_test_entity_test_load($eid, $evid);
     foreach ($available_langcodes as $langcode => $value) {
-      $passed = $entity->getTranslation($langcode)->{$field_name}->value == $value + 1;
-      $this->assertTrue($passed, format_string('The @language translation for revision @revision was correctly stored', array('@language' => $langcode, '@revision' => $entity->getRevisionId())));
+      $passed = isset($entity->{$field_name}[$langcode]) && $entity->{$field_name}[$langcode][0]['value'] == $value + 1;
+      $this->assertTrue($passed, format_string('The @language translation for revision @revision was correctly stored', array('@language' => $langcode, '@revision' => $entity->ftvid)));
     }
   }
 }
diff --git a/core/modules/field/tests/modules/field_test/field_test.entity.inc b/core/modules/field/tests/modules/field_test/field_test.entity.inc
index 4cea03a..7802bda 100644
--- a/core/modules/field/tests/modules/field_test/field_test.entity.inc
+++ b/core/modules/field/tests/modules/field_test/field_test.entity.inc
@@ -29,6 +29,48 @@ function field_test_entity_info_alter(&$entity_info) {
 }
 
 /**
+ * Implements hook_entity_view_mode_info_alter().
+ */
+function field_test_entity_view_mode_info_alter(&$view_modes) {
+  $entity_info = entity_get_info();
+  foreach ($entity_info as $entity_type => $info) {
+    if ($entity_info[$entity_type]['module'] == 'field_test') {
+      $view_modes[$entity_type] = array(
+        'full' => array(
+          'label' => t('Full object'),
+          'status' => TRUE,
+        ),
+        'teaser' => array(
+          'label' => t('Teaser'),
+          'status' => TRUE,
+        ),
+      );
+    }
+  }
+}
+
+/**
+ * Implements hook_entity_bundle_info().
+ */
+function field_test_entity_bundle_info() {
+  $bundles = array();
+
+  $entity_info = entity_get_info();
+  foreach ($entity_info as $entity_type => $info) {
+    if ($info['module'] == 'field_test') {
+      $bundles[$entity_type] = Drupal::state()->get('field_test_bundles') ?: array('test_bundle' => array('label' => 'Test Bundle'));
+    }
+  }
+
+  $bundles['test_entity_bundle']['test_entity_2'] = array('label' => 'Test entity 2');
+
+  $bundles['test_entity_bundle_key']['bundle1'] = array('label' => 'Bundle1');
+  $bundles['test_entity_bundle_key']['bundle2'] = array('label' => 'Bundle2');
+
+  return $bundles;
+}
+
+/**
  * Helper function to enable entity translations.
  */
 function field_test_entity_info_translatable($entity_type = NULL, $translatable = NULL) {
@@ -42,6 +84,142 @@ function field_test_entity_info_translatable($entity_type = NULL, $translatable
 }
 
 /**
+ * Creates a new bundle for test_entity entities.
+ *
+ * @param $bundle
+ *   The machine-readable name of the bundle.
+ * @param $text
+ *   The human-readable name of the bundle. If none is provided, the machine
+ *   name will be used.
+ */
+function field_test_create_bundle($bundle, $text = NULL) {
+  $bundles = Drupal::state()->get('field_test.bundles') ?: array('test_bundle' => array('label' => 'Test Bundle'));
+  $bundles += array($bundle => array('label' => $text ? $text : $bundle));
+  Drupal::state()->set('field_test.bundles', $bundles);
+
+  $info = entity_get_info();
+  foreach ($info as $type => $type_info) {
+    if ($type_info['module'] == 'field_test') {
+      entity_invoke_bundle_hook('create', $type, $bundle);
+    }
+  }
+}
+
+/**
+ * Renames a bundle for test_entity entities.
+ *
+ * @param $bundle_old
+ *   The machine-readable name of the bundle to rename.
+ * @param $bundle_new
+ *   The new machine-readable name of the bundle.
+ */
+function field_test_rename_bundle($bundle_old, $bundle_new) {
+  $bundles = Drupal::state()->get('field_test.bundles') ?: array('test_bundle' => array('label' => 'Test Bundle'));
+  $bundles[$bundle_new] = $bundles[$bundle_old];
+  unset($bundles[$bundle_old]);
+  Drupal::state()->set('field_test.bundles', $bundles);
+
+  $info = entity_get_info();
+  foreach ($info as $type => $type_info) {
+    if ($type_info['module'] == 'field_test') {
+      entity_invoke_bundle_hook('rename', $type, $bundle_old, $bundle_new);
+    }
+  }
+}
+
+/**
+ * Deletes a bundle for test_entity objects.
+ *
+ * @param $bundle
+ *   The machine-readable name of the bundle to delete.
+ */
+function field_test_delete_bundle($bundle) {
+  $bundles = Drupal::state()->get('field_test.bundles') ?: array('test_bundle' => array('label' => 'Test Bundle'));
+  unset($bundles[$bundle]);
+  Drupal::state()->set('field_test.bundles', $bundles);
+
+  $info = entity_get_info();
+  foreach ($info as $type => $type_info) {
+    if ($type_info['module'] == 'field_test') {
+      entity_invoke_bundle_hook('delete', $type, $bundle);
+    }
+  }
+}
+
+/**
+ * Creates a basic test_entity entity.
+ */
+function field_test_create_entity($id = 1, $vid = 1, $bundle = 'test_bundle', $label = '') {
+  $entity = entity_create('test_entity', array('fttype' => $bundle));
+  // Only set id and vid properties if they don't come as NULL (creation form).
+  if (isset($id)) {
+    $entity->ftid = $id;
+  }
+  if (isset($vid)) {
+    $entity->ftvid = $vid;
+    // Flag to make sure that the provided vid is used for a new revision.
+    $entity->use_provided_revision_id = $vid;
+  }
+
+  $label = !empty($label) ? $label : $bundle . ' label';
+  $entity->ftlabel = $label;
+  // Make sure the entity will saved even if a primary key is provided.
+  $entity->enforceIsNew();
+  $entity->setNewRevision();
+  return $entity;
+}
+
+/**
+ * Loads a test_entity.
+ *
+ * @param $ftid
+ *   The id of the entity to load.
+ * @param $ftvid
+ *   (Optional) The revision id of the entity to load. If not specified, the
+ *   current revision will be used.
+ * @return
+ *   The loaded entity.
+ */
+function field_test_entity_test_load($ftid, $ftvid = NULL) {
+  // Prevent this from being called as hook_entity_test_load().
+  if (is_array($ftid)) {
+    return;
+  }
+  $ids = (isset($ftid) ? array($ftid) : array());
+  $conditions = (isset($ftvid) ? array('ftvid' => $ftvid) : array());
+  $test_entity = entity_load_multiple('test_entity', $ids, $conditions);
+  return $test_entity ? reset($test_entity) : FALSE;
+}
+
+/**
+ * Saves a test_entity.
+ *
+ * @param \Drupal\Core\Entity\EntityInterface $entity
+ *   The entity to save.
+ */
+function field_test_entity_save(EntityInterface $entity) {
+  $entity->save();
+}
+
+/**
+ * Menu callback: displays the 'Add new test_entity' form.
+ */
+function field_test_entity_add($fttype) {
+  $fttype = str_replace('-', '_', $fttype);
+  $entity = field_test_create_entity(NULL, NULL, $fttype);
+  drupal_set_title(t('Create test_entity @bundle', array('@bundle' => $fttype)), PASS_THROUGH);
+  return Drupal::entityManager()->getForm($entity);
+}
+
+/**
+ * Menu callback: displays the 'Edit exiisting test_entity' form.
+ */
+function field_test_entity_edit(TestEntity $entity) {
+  drupal_set_title(t('test_entity @ftid revision @ftvid', array('@ftid' => $entity->ftid, '@ftvid' => $entity->ftvid)), PASS_THROUGH);
+  return Drupal::entityManager()->getForm($entity);
+}
+
+/**
  * Form combining two separate entities.
  */
 function field_test_entity_nested_form($form, &$form_state, $entity_1, $entity_2) {
@@ -100,11 +278,11 @@ function field_test_entity_nested_form_validate($form, &$form_state) {
 function field_test_entity_nested_form_submit($form, &$form_state) {
   $entity_1 = entity_create('entity_test', $form_state['values']);
   field_attach_extract_form_values($entity_1, $form, $form_state);
-  $entity_1->save();
+  field_test_entity_save($entity_1);
 
   $entity_2 = entity_create('entity_test', $form_state['values']['entity_2']);
   field_attach_extract_form_values($entity_2, $form['entity_2'], $form_state);
-  $entity_2->save();
+  field_test_entity_save($entity_2);
 
   drupal_set_message(t('test_entities @id_1 and @id_2 have been updated.', array('@id_1' => $entity_1->id(), '@id_2' => $entity_2->id())));
 }
diff --git a/core/modules/field/tests/modules/field_test/field_test.install b/core/modules/field/tests/modules/field_test/field_test.install
index a079829..b0a15a2 100644
--- a/core/modules/field/tests/modules/field_test/field_test.install
+++ b/core/modules/field/tests/modules/field_test/field_test.install
@@ -14,6 +14,103 @@ function field_test_install() {
 }
 
 /**
+ * Implements hook_schema().
+ */
+function field_test_schema() {
+  $schema['test_entity'] = array(
+    'description' => 'The base table for test_entities.',
+    'fields' => array(
+      'ftid' => array(
+        'description' => 'The primary identifier for a test_entity.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'ftvid' => array(
+        'description' => 'The current {test_entity_revision}.ftvid version identifier.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'fttype' => array(
+        'description' => 'The type of this test_entity.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'ftlabel' => array(
+        'description' => 'The label of this test_entity.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'unique keys' => array(
+      'ftvid' => array('ftvid'),
+    ),
+    'primary key' => array('ftid'),
+  );
+  $schema['test_entity_bundle_key'] = array(
+    'description' => 'The base table for test entities with a bundle key.',
+    'fields' => array(
+      'ftid' => array(
+        'description' => 'The primary indentifier for a test_entity_bundle_key.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'fttype' => array(
+        'description' => 'The type of this test_entity.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => FALSE,
+        'default' => '',
+      ),
+    ),
+  );
+  $schema['test_entity_bundle'] = array(
+    'description' => 'The base table for test entities with a bundle.',
+    'fields' => array(
+      'ftid' => array(
+        'description' => 'The primary indentifier for a test_entity_bundle.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+    ),
+  );
+  $schema['test_entity_revision'] = array(
+    'description' => 'Stores information about each saved version of a {test_entity}.',
+    'fields' => array(
+      'ftid' => array(
+        'description' => 'The {test_entity} this version belongs to.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'ftvid' => array(
+        'description' => 'The primary identifier for this version.',
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+    ),
+    'indexes' => array(
+      'nid' => array('ftid'),
+    ),
+    'primary key' => array('ftvid'),
+  );
+
+  return $schema;
+}
+
+/**
  * Implements hook_field_schema().
  */
 function field_test_field_schema($field) {
diff --git a/core/modules/field/tests/modules/field_test/field_test.module b/core/modules/field/tests/modules/field_test/field_test.module
index 5ac9e9d..0f111de 100644
--- a/core/modules/field/tests/modules/field_test/field_test.module
+++ b/core/modules/field/tests/modules/field_test/field_test.module
@@ -25,6 +25,10 @@
  */
 function field_test_permission() {
   $perms = array(
+    'access field_test content' => array(
+      'title' => t('Access field_test content'),
+      'description' => t('View published field_test content.'),
+    ),
     'view test_view_field content' => array(
       'title' => t('View test field content'),
       'description' => t('View published test_view_field content.'),
@@ -42,6 +46,24 @@ function field_test_permission() {
  */
 function field_test_menu() {
   $items = array();
+
+  foreach (entity_get_bundles('test_entity') as $bundle_name => $bundle_info) {
+    $items['test-entity/add/' . $bundle_name] = array(
+      'title' => t('Add %bundle test_entity', array('%bundle' => $bundle_info['label'])),
+      'page callback' => 'field_test_entity_add',
+      'page arguments' => array(2),
+      'access arguments' => array('administer field_test content'),
+      'type' => MENU_NORMAL_ITEM,
+    );
+  }
+  $items['test-entity/manage/%field_test_entity_test/edit'] = array(
+    'title' => 'Edit test entity',
+    'page callback' => 'field_test_entity_edit',
+    'page arguments' => array(2),
+    'access arguments' => array('administer field_test content'),
+    'type' => MENU_NORMAL_ITEM,
+  );
+
   $items['test-entity/nested/%entity_test/%entity_test'] = array(
     'title' => 'Nested entity form',
     'page callback' => 'drupal_get_form',
@@ -178,7 +200,7 @@ function field_test_field_widget_form_alter(&$element, &$form_state, $context) {
 function field_test_query_efq_table_prefixing_test_alter(&$query) {
   // Add an additional join onto the entity base table. This will cause an
   // exception if the EFQ does not properly prefix the base table.
-  $query->join('entity_test','et2','%alias.id = entity_test.id');
+  $query->join('test_entity','te2','%alias.ftid = test_entity.ftid');
 }
 
 
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleKeyTestEntity.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleKeyTestEntity.php
new file mode 100644
index 0000000..d0e715a
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleKeyTestEntity.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\field_test\Plugin\Core\Entity\BundleKeyTestEntity.
+ */
+
+namespace Drupal\field_test\Plugin\Core\Entity;
+
+use Drupal\Core\Entity\Annotation\EntityType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Test entity class.
+ *
+ * @EntityType(
+ *   id = "test_entity_bundle_key",
+ *   label = @Translation("Test Entity with a bundle key"),
+ *   module = "field_test",
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Entity\DatabaseStorageController",
+ *     "form" = {
+ *       "default" = "Drupal\field_test\TestEntityFormController"
+ *     }
+ *   },
+ *   field_cache = FALSE,
+ *   base_table = "test_entity_bundle_key",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "ftid",
+ *     "bundle" = "fttype"
+ *   }
+ * )
+ */
+class BundleKeyTestEntity extends TestEntity {
+
+}
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleTestEntity.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleTestEntity.php
new file mode 100644
index 0000000..5ad5777
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/BundleTestEntity.php
@@ -0,0 +1,37 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\field_test\Plugin\Core\Entity\BundleTestEntity.
+ */
+
+namespace Drupal\field_test\Plugin\Core\Entity;
+
+use Drupal\Core\Entity\Annotation\EntityType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Test entity class.
+ *
+ * @EntityType(
+ *   id = "test_entity_bundle",
+ *   label = @Translation("Test Entity with a specified bundle"),
+ *   module = "field_test",
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Entity\DatabaseStorageController",
+ *     "form" = {
+ *       "default" = "Drupal\field_test\TestEntityFormController"
+ *     }
+ *   },
+ *   field_cache = FALSE,
+ *   base_table = "test_entity_bundle",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "ftid",
+ *     "bundle" = "fttype"
+ *   }
+ * )
+ */
+class BundleTestEntity extends TestEntity {
+
+}
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/CacheableTestEntity.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/CacheableTestEntity.php
new file mode 100644
index 0000000..351d7c0
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/CacheableTestEntity.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\field_test\Plugin\Core\Entity\CacheableTestEntity.
+ */
+
+namespace Drupal\field_test\Plugin\Core\Entity;
+
+use Drupal\Core\Entity\Annotation\EntityType;
+use Drupal\Core\Annotation\Translation;
+
+/**
+ * Test entity class.
+ *
+ * @EntityType(
+ *   id = "test_cacheable_entity",
+ *   label = @Translation("Test Entity, cacheable"),
+ *   module = "field_test",
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Entity\DatabaseStorageController"
+ *   },
+ *   field_cache = TRUE,
+ *   base_table = "test_entity",
+ *   revision_table = "test_entity_revision",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "ftid",
+ *     "revision" = "ftvid",
+ *     "bundle" = "fttype"
+ *   }
+ * )
+ */
+class CacheableTestEntity extends TestEntity {
+
+}
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php
new file mode 100644
index 0000000..1d8d9d0
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/Plugin/Core/Entity/TestEntity.php
@@ -0,0 +1,102 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\field_test\Plugin\Core\Entity\TestEntity.
+ */
+
+namespace Drupal\field_test\Plugin\Core\Entity;
+
+use Drupal\Core\Entity\Entity;
+use Drupal\Core\Entity\Annotation\EntityType;
+use Drupal\Core\Annotation\Translation;
+use Drupal\Core\Entity\EntityStorageControllerInterface;
+
+/**
+ * Test entity class.
+ *
+ * @EntityType(
+ *   id = "test_entity",
+ *   label = @Translation("Test Entity"),
+ *   module = "field_test",
+ *   controllers = {
+ *     "storage" = "Drupal\Core\Entity\DatabaseStorageController",
+ *     "render" = "Drupal\Core\Entity\EntityRenderController",
+ *     "form" = {
+ *       "default" = "Drupal\field_test\TestEntityFormController"
+ *     }
+ *   },
+ *   field_cache = FALSE,
+ *   base_table = "test_entity",
+ *   revision_table = "test_entity_revision",
+ *   fieldable = TRUE,
+ *   entity_keys = {
+ *     "id" = "ftid",
+ *     "revision" = "ftvid",
+ *     "bundle" = "fttype"
+ *   }
+ * )
+ */
+class TestEntity extends Entity {
+
+  /**
+   * Primary key.
+   *
+   * @var integer
+   */
+  public $ftid;
+
+  /**
+   * Revision key.
+   *
+   * @var integer
+   */
+  public $ftvid;
+
+  /**
+   * Bundle
+   *
+   * @var string
+   */
+  public $fttype;
+
+  /**
+   * Label property
+   *
+   * @var string
+   */
+  public $ftlabel;
+
+  /**
+   * Overrides Drupal\Core\Entity\Entity::id().
+   */
+  public function id() {
+    return $this->ftid;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\Entity::getRevisionId().
+   */
+  public function getRevisionId() {
+    return $this->ftvid;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\Entity::bundle().
+   */
+  public function bundle() {
+    return !empty($this->fttype) ? $this->fttype : $this->entityType();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function preSaveRevision(EntityStorageControllerInterface $storage_controller, \stdClass $record) {
+    // Allow for predefined revision ids.
+    if (!empty($record->use_provided_revision_id)) {
+      $record->ftvid = $record->use_provided_revision_id;
+    }
+  }
+
+}
+
diff --git a/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php
new file mode 100644
index 0000000..d5a4508
--- /dev/null
+++ b/core/modules/field/tests/modules/field_test/lib/Drupal/field_test/TestEntityFormController.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\field_test\TestEntityFormController.
+ */
+
+namespace Drupal\field_test;
+
+use Drupal\Core\Entity\EntityFormController;
+
+/**
+ * Form controller for the test entity edit forms.
+ */
+class TestEntityFormController extends EntityFormController {
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::form().
+   */
+  public function form(array $form, array &$form_state) {
+    $form = parent::form($form, $form_state);
+
+    $entity = $this->entity;
+    if (!$entity->isNew()) {
+      $form['revision'] = array(
+        '#access' => user_access('administer field_test content'),
+        '#type' => 'checkbox',
+        '#title' => t('Create new revision'),
+        '#default_value' => FALSE,
+        '#weight' => 100,
+      );
+    }
+    return $form;
+  }
+
+  /**
+   * Overrides Drupal\Core\Entity\EntityFormController::save().
+   */
+  public function save(array $form, array &$form_state) {
+    $entity = $this->entity;
+    $is_new = $entity->isNew();
+    $entity->save();
+
+    $message = $is_new ? t('test_entity @id has been created.', array('@id' => $entity->id())) : t('test_entity @id has been updated.', array('@id' => $entity->id()));
+    drupal_set_message($message);
+
+    if ($entity->id()) {
+      $form_state['redirect'] = 'test-entity/manage/' . $entity->id() . '/edit';
+    }
+    else {
+      // Error on save.
+      drupal_set_message(t('The entity could not be saved.'), 'error');
+      $form_state['rebuild'] = TRUE;
+    }
+  }
+}
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.entity_test.field_test_import.yml b/core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle.field_test_import.yml
similarity index 71%
rename from core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.entity_test.field_test_import.yml
rename to core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle.field_test_import.yml
index 61a65d8..e51b394 100644
--- a/core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.entity_test.field_test_import.yml
+++ b/core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle.field_test_import.yml
@@ -1,8 +1,8 @@
-id: entity_test.entity_test.field_test_import
+id: test_entity.test_bundle.field_test_import
 langcode: und
 field_name: field_test_import
-entity_type: entity_test
-bundle: entity_test
+entity_type: test_entity
+bundle: test_bundle
 label: 'Test import field'
 description: ''
 required: '0'
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.test_bundle.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle.field_test_import_2.yml
similarity index 82%
rename from core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.test_bundle.field_test_import_2.yml
rename to core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle.field_test_import_2.yml
index 3312ee6..c91f72b 100644
--- a/core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.test_bundle.field_test_import_2.yml
+++ b/core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle.field_test_import_2.yml
@@ -1,7 +1,7 @@
-id: entity_test.test_bundle.field_test_import_2
+id: test_entity.test_bundle.field_test_import_2
 langcode: und
 field_name: field_test_import_2
-entity_type: entity_test
+entity_type: test_entity
 bundle: test_bundle
 label: 'Test import field 2 on test bundle'
 description: ''
diff --git a/core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.entity_test.field_test_import_2.yml b/core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle_2.field_test_import_2.yml
similarity index 66%
rename from core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.entity_test.field_test_import_2.yml
rename to core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle_2.field_test_import_2.yml
index 0f9883d..a5f7541 100644
--- a/core/modules/field/tests/modules/field_test_config/config/field.instance.entity_test.entity_test.field_test_import_2.yml
+++ b/core/modules/field/tests/modules/field_test_config/config/field.instance.test_entity.test_bundle_2.field_test_import_2.yml
@@ -1,9 +1,9 @@
-id: entity_test.entity_test.field_test_import_2
+id: test_entity.test_bundle_2.field_test_import_2
 langcode: und
 field_name: field_test_import_2
-entity_type: entity_test
-bundle: entity_test
-label: 'Test import field 2 on entity_test bundle'
+entity_type: test_entity
+bundle: test_bundle_2
+label: 'Test import field 2 on test bundle 2'
 description: ''
 required: '0'
 default_value: {  }
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.entity_test.field_test_import_staging.yml b/core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle.field_test_import_staging.yml
similarity index 74%
rename from core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.entity_test.field_test_import_staging.yml
rename to core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle.field_test_import_staging.yml
index 2be5d9c..f751ad5 100644
--- a/core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.entity_test.field_test_import_staging.yml
+++ b/core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle.field_test_import_staging.yml
@@ -1,9 +1,9 @@
-id: entity_test.entity_test.field_test_import_staging
+id: test_entity.test_bundle.field_test_import_staging
 uuid: ea711065-6940-47cd-813d-618f64095481
 langcode: und
 field_uuid: 0bf654cc-f14a-4881-b94c-76959e47466b
-entity_type: entity_test
-bundle: entity_test
+entity_type: test_entity
+bundle: test_bundle
 label: 'Import from staging'
 description: ''
 required: '0'
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.test_bundle.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle.field_test_import_staging_2.yml
similarity index 83%
rename from core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.test_bundle.field_test_import_staging_2.yml
rename to core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle.field_test_import_staging_2.yml
index d003875..c3bb7a5 100644
--- a/core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.test_bundle.field_test_import_staging_2.yml
+++ b/core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle.field_test_import_staging_2.yml
@@ -1,8 +1,8 @@
-id: entity_test.test_bundle.field_test_import_staging_2
+id: test_entity.test_bundle.field_test_import_staging_2
 uuid: f07794a2-d7cc-45b6-b40d-13cf021b5552
 langcode: und
 field_uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00
-entity_type: entity_test
+entity_type: test_entity
 bundle: test_bundle
 label: 'Test import field 2 on test bundle'
 description: ''
diff --git a/core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.test_bundle_2.field_test_import_staging_2.yml b/core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle_2.field_test_import_staging_2.yml
similarity index 83%
rename from core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.test_bundle_2.field_test_import_staging_2.yml
rename to core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle_2.field_test_import_staging_2.yml
index 7eb124e..63ad202 100644
--- a/core/modules/field/tests/modules/field_test_config/staging/field.instance.entity_test.test_bundle_2.field_test_import_staging_2.yml
+++ b/core/modules/field/tests/modules/field_test_config/staging/field.instance.test_entity.test_bundle_2.field_test_import_staging_2.yml
@@ -1,8 +1,8 @@
-id: entity_test.test_bundle_2.field_test_import_staging_2
+id: test_entity.test_bundle_2.field_test_import_staging_2
 uuid: 49d6dd19-5097-443d-8f00-fc79525bebce
 langcode: und
 field_uuid: 2165d9aa-9a0c-41a1-be02-2a49f3405c00
-entity_type: entity_test
+entity_type: test_entity
 bundle: test_bundle_2
 label: 'Test import field 2 on test bundle 2'
 description: ''
diff --git a/core/modules/field_sql_storage/field_sql_storage.services.yml b/core/modules/field_sql_storage/field_sql_storage.services.yml
new file mode 100644
index 0000000..42126e4
--- /dev/null
+++ b/core/modules/field_sql_storage/field_sql_storage.services.yml
@@ -0,0 +1,4 @@
+services:
+  entity.query.field_sql_storage:
+    class: Drupal\field_sql_storage\Entity\QueryFactory
+    arguments: ['@database']
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Condition.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Condition.php
similarity index 96%
rename from core/lib/Drupal/Core/Entity/Query/Sql/Condition.php
rename to core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Condition.php
index 7323586..30ac520 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Condition.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Condition.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\Query\Sql\Condition.
+ * Definition of Drupal\field_sql_storage\Query\ConditionSql.
  */
 
-namespace Drupal\Core\Entity\Query\Sql;
+namespace Drupal\field_sql_storage\Entity;
 
 use Drupal\Core\Entity\Query\ConditionBase;
 use Drupal\Core\Entity\Query\ConditionInterface;
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/ConditionAggregate.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/ConditionAggregate.php
similarity index 96%
rename from core/lib/Drupal/Core/Entity/Query/Sql/ConditionAggregate.php
rename to core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/ConditionAggregate.php
index cd83691..eb5290e 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/ConditionAggregate.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/ConditionAggregate.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\Query\Sql\ConditionAggregate.
+ * Contains \Drupal\field_sql_storage\Query\ConditionAggregate.
  */
 
-namespace Drupal\Core\Entity\Query\Sql;
+namespace Drupal\field_sql_storage\Entity;
 
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\Query\ConditionAggregateBase;
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Query.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php
similarity index 97%
rename from core/lib/Drupal/Core/Entity/Query/Sql/Query.php
rename to core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php
index 6fbae92..930d367 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Query.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Query.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\Query\Sql\Query.
+ * Definition of Drupal\field_sql_storage\Entity\Query.
  */
 
-namespace Drupal\Core\Entity\Query\Sql;
+namespace Drupal\field_sql_storage\Entity;
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityManager;
@@ -111,7 +111,7 @@ public function execute() {
    * @throws \Drupal\Core\Entity\Query\QueryException
    *   Thrown if the base table does not exists.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\Query
+   * @return \Drupal\field_sql_storage\Entity\Query
    *   Returns the called object.
    */
   protected function prepare() {
@@ -173,7 +173,7 @@ protected function prepare() {
   /**
    * Compiles the conditions.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\Query
+   * @return \Drupal\field_sql_storage\Entity\Query
    *   Returns the called object.
    */
   protected function compile() {
@@ -184,7 +184,7 @@ protected function compile() {
   /**
    * Adds the sort to the build query.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\Query
+   * @return \Drupal\field_sql_storage\Entity\Query
    *   Returns the called object.
    */
   protected function addSort() {
@@ -242,7 +242,7 @@ protected function addSort() {
   /**
    * Finish the query by adding fields, GROUP BY and range.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\Query
+   * @return \Drupal\field_sql_storage\Entity\Query
    *   Returns the called object.
    */
   protected function finish() {
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/QueryAggregate.php
similarity index 89%
rename from core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php
rename to core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/QueryAggregate.php
index 28455ca..c8bbb81 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/QueryAggregate.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/QueryAggregate.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\Query\Sql\QueryAggregate.
+ * Contains \Drupal\field_sql_storage\Entity\QueryAggregate.
  */
 
-namespace Drupal\Core\Entity\Query\Sql;
+namespace Drupal\field_sql_storage\Entity;
 
 use Drupal\Core\Entity\Query\QueryAggregateInterface;
 
@@ -39,7 +39,7 @@ public function execute() {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\Query\Sql::prepare().
+   * Overrides \Drupal\field_sql_storage\Entity::prepare().
    */
   public function prepare() {
     parent::prepare();
@@ -73,7 +73,7 @@ public function notExistsAggregate($field, $function, $langcode = NULL) {
   /**
    * Adds the aggregations to the query.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\QueryAggregate
+   * @return \Drupal\field_sql_storage\Entity\QueryAggregate
    *   Returns the called object.
    */
   protected function addAggregate() {
@@ -89,7 +89,7 @@ protected function addAggregate() {
   /**
    * Builds the aggregation conditions part of the query.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\QueryAggregate
+   * @return \Drupal\field_sql_storage\Entity\QueryAggregate
    *   Returns the called object.
    */
   protected function compileAggregate() {
@@ -100,7 +100,7 @@ protected function compileAggregate() {
   /**
    * Adds the groupby values to the actual query.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\QueryAggregate
+   * @return \Drupal\field_sql_storage\Entity\QueryAggregate
    *   Returns the called object.
    */
   protected function addGroupBy() {
@@ -118,7 +118,7 @@ protected function addGroupBy() {
   /**
    * Builds the aggregation sort part of the query.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\QueryAggregate
+   * @return \Drupal\field_sql_storage\Entity\QueryAggregate
    *   Returns the called object.
    */
   protected function addSortAggregate() {
@@ -132,7 +132,7 @@ protected function addSortAggregate() {
 
 
   /**
-   * Overrides \Drupal\Core\Entity\Query\Sql\Query::finish().
+   * Overrides \Drupal\field_sql_storage\Entity\Query::finish().
    *
    * Adds the sql expressions to the query.
    */
@@ -165,7 +165,7 @@ function createSqlAlias($field, $sql_field) {
   }
 
   /**
-   * Overrides \Drupal\Core\Entity\Query\Sql\Query::result().
+   * Overrides \Drupal\field_sql_storage\Entity\Query::result().
    *
    * @return array|int
    *   Returns the aggregated result, or a number if it's a count query.
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/QueryFactory.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/QueryFactory.php
similarity index 84%
rename from core/lib/Drupal/Core/Entity/Query/Sql/QueryFactory.php
rename to core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/QueryFactory.php
index 2a45e05..48f8f30 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/QueryFactory.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/QueryFactory.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\Query\Sql\QueryFactory.
+ * Contains \Drupal\field_sql_storage\Entity\QueryFactory.
  */
 
-namespace Drupal\Core\Entity\Query\Sql;
+namespace Drupal\field_sql_storage\Entity;
 
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityManager;
@@ -14,8 +14,8 @@
 /**
  * Factory class creating entity query objects for the SQL backend.
  *
- * @see \Drupal\Core\Entity\Query\Sql\Query
- * @see \Drupal\Core\Entity\Query\Sql\QueryAggregate
+ * @see \Drupal\field_sql_storage\Entity\Query
+ * @see \Drupal\field_sql_storage\Entity\QueryAggregate
  */
 class QueryFactory implements QueryFactoryInterface {
 
@@ -45,7 +45,7 @@ function __construct(Connection $connection) {
    *   - AND: all of the conditions on the query need to match.
    *   - OR: at least one of the conditions on the query need to match.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\Query
+   * @return \Drupal\field_sql_storage\Entity\Query
    *   The factored query.
    */
   function get($entity_type, $conjunction, EntityManager $entity_manager) {
@@ -61,7 +61,7 @@ function get($entity_type, $conjunction, EntityManager $entity_manager) {
    *   - AND: all of the conditions on the query need to match.
    *   - OR: at least one of the conditions on the query need to match.
    *
-   * @return \Drupal\Core\Entity\Query\Sql\QueryAggregate
+   * @return \Drupal\field_sql_storage\Entity\QueryAggregate
    *   The factored aggregation query.
    */
   function getAggregate($entity_type, $conjunction, EntityManager $entity_manager) {
diff --git a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php
similarity index 99%
rename from core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
rename to core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php
index f346129..11aebc0 100644
--- a/core/lib/Drupal/Core/Entity/Query/Sql/Tables.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Entity/Tables.php
@@ -2,10 +2,10 @@
 
 /**
  * @file
- * Contains \Drupal\Core\Entity\Query\Sql\Tables.
+ * Definition of Drupal\field_sql_storage\Entity\Tables.
  */
 
-namespace Drupal\Core\Entity\Query\Sql;
+namespace Drupal\field_sql_storage\Entity;
 
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Entity\Query\QueryException;
diff --git a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
index 737daf3..00ebd9c 100644
--- a/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
+++ b/core/modules/field_sql_storage/lib/Drupal/field_sql_storage/Tests/FieldSqlStorageTest.php
@@ -26,7 +26,7 @@ class FieldSqlStorageTest extends EntityUnitTestBase {
    *
    * @var array
    */
-  public static $modules = array('field_sql_storage', 'field', 'field_test', 'text', 'number', 'entity_test');
+  public static $modules = array('field_test', 'text', 'number');
 
   /**
    * The name of the created field.
@@ -66,8 +66,7 @@ public static function getInfo() {
 
   function setUp() {
     parent::setUp();
-    $this->installSchema('entity_test', array('entity_test_rev', 'entity_test_rev_revision'));
-    $entity_type = 'entity_test_rev';
+    $this->installSchema('field_test', array('test_entity', 'test_entity_revision', 'test_entity_bundle'));
 
     $this->field_name = strtolower($this->randomName());
     $this->field = entity_create('field_entity', array(
@@ -78,8 +77,8 @@ function setUp() {
     $this->field->save();
     $this->instance = entity_create('field_instance', array(
       'field_name' => $this->field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $entity_type
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle'
     ));
     $this->instance->save();
     $this->table = _field_sql_storage_tablename($this->field);
@@ -91,7 +90,7 @@ function setUp() {
    * field_load_revision works correctly.
    */
   function testFieldAttachLoad() {
-    $entity_type = 'entity_test_rev';
+    $entity_type = 'test_entity';
     $eid = 0;
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
@@ -118,33 +117,27 @@ function testFieldAttachLoad() {
     $query->execute();
 
     // Load the "most current revision"
-    $entity = entity_create($entity_type, array(
-      'id' => 0,
-      'revision_id' => 0,
-    ));
+    $entity = field_test_create_entity($eid, 0, $this->instance['bundle']);
     field_attach_load($entity_type, array($eid => $entity));
     foreach ($values[0] as $delta => $value) {
       if ($delta < $this->field['cardinality']) {
-        $this->assertEqual($entity->{$this->field_name}[$delta]->value, $value, "Value $delta is loaded correctly for current revision");
+        $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value $delta is loaded correctly for current revision");
       }
       else {
-        $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}), "No extraneous value gets loaded for current revision.");
+        $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}[$langcode]), "No extraneous value gets loaded for current revision.");
       }
     }
 
     // Load every revision
     for ($evid = 0; $evid < 4; ++$evid) {
-      $entity = entity_create($entity_type, array(
-        'id' => $eid,
-        'revision_id' => $evid,
-      ));
+      $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
       field_attach_load_revision($entity_type, array($eid => $entity));
       foreach ($values[$evid] as $delta => $value) {
         if ($delta < $this->field['cardinality']) {
-          $this->assertEqual($entity->{$this->field_name}[$delta]->value, $value, "Value $delta for revision $evid is loaded correctly");
+          $this->assertEqual($entity->{$this->field_name}[$langcode][$delta]['value'], $value, "Value $delta for revision $evid is loaded correctly");
         }
         else {
-          $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}), "No extraneous value gets loaded for revision $evid.");
+          $this->assertFalse(array_key_exists($delta, $entity->{$this->field_name}[$langcode]), "No extraneous value gets loaded for revision $evid.");
         }
       }
     }
@@ -153,10 +146,7 @@ function testFieldAttachLoad() {
     // loaded.
     $eid = $evid = 1;
     $unavailable_langcode = 'xx';
-    $entity = entity_create($entity_type, array(
-      'id' => $eid,
-      'revision_id' => $evid,
-    ));
+    $entity = field_test_create_entity($eid, $evid, $this->instance['bundle']);
     $values = array($entity_type, $eid, $evid, 0, $unavailable_langcode, mt_rand(1, 127));
     db_insert($this->table)->fields($columns)->values($values)->execute();
     db_insert($this->revision_table)->fields($columns)->values($values)->execute();
@@ -169,11 +159,8 @@ function testFieldAttachLoad() {
    * written when using insert and update.
    */
   function testFieldAttachInsertAndUpdate() {
-    $entity_type = 'entity_test_rev';
-    $entity = entity_create($entity_type, array(
-      'id' => 0,
-      'revision_id' => 0,
-    ));
+    $entity_type = 'test_entity';
+    $entity = field_test_create_entity(0, 0, $this->instance['bundle']);
     $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Test insert.
@@ -183,7 +170,7 @@ function testFieldAttachInsertAndUpdate() {
     for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
     }
-    $entity->{$this->field_name} = $rev_values[0] = $values;
+    $entity->{$this->field_name}[$langcode] = $rev_values[0] = $values;
     field_attach_insert($entity);
 
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
@@ -197,17 +184,13 @@ function testFieldAttachInsertAndUpdate() {
     }
 
     // Test update.
-    $entity = entity_create($entity_type, array(
-      'id' => 0,
-      'revision_id' => 1,
-    ));
+    $entity = field_test_create_entity(0, 1, $this->instance->bundle);
     $values = array();
     // Note: we try to update one extra value ('<=' instead of '<').
     for ($delta = 0; $delta <= $this->field['cardinality']; $delta++) {
       $values[$delta]['value'] = mt_rand(1, 127);
     }
-    $rev_values[1] = $values;
-    $entity->{$this->field_name}->setValue($values);
+    $entity->{$this->field_name}[$langcode] = $rev_values[1] = $values;
     field_attach_update($entity);
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     foreach ($values as $delta => $value) {
@@ -247,21 +230,19 @@ function testFieldAttachInsertAndUpdate() {
     }
 
     // Check that update with an empty $entity->$field_name empties the field.
-    $entity->getBCEntity()->{$this->field_name} = NULL;
+    $entity->{$this->field_name} = NULL;
     field_attach_update($entity);
     $rows = db_select($this->table, 't')->fields('t')->execute()->fetchAllAssoc('delta', PDO::FETCH_ASSOC);
     $this->assertEqual(count($rows), 0, t("Update with an empty field_name entry empties the field."));
   }
 
   /**
-   * Tests insert and update with empty and NULL fields.
+   * Tests insert and update with missing or NULL fields.
    */
   function testFieldAttachSaveMissingData() {
-    $entity_type = 'entity_test_rev';
-    $entity = entity_create($entity_type, array(
-      'id' => 0,
-      'revision_id' => 0,
-    ));
+    $entity_type = 'test_entity';
+    $entity = field_test_create_entity(0, 0, $this->instance->bundle);
+    $langcode = Language::LANGCODE_NOT_SPECIFIED;
 
     // Insert: Field is missing
     field_attach_insert($entity);
@@ -281,7 +262,7 @@ function testFieldAttachSaveMissingData() {
     $this->assertEqual($count, 0, 'NULL field results in no inserts');
 
     // Add some real data
-    $entity->{$this->field_name}->value = 1;
+    $entity->{$this->field_name}[$langcode] = array(0 => array('value' => 1));
     field_attach_insert($entity);
     $count = db_select($this->table)
       ->countQuery()
@@ -289,8 +270,17 @@ function testFieldAttachSaveMissingData() {
       ->fetchField();
     $this->assertEqual($count, 1, 'Field data saved');
 
+    // Update: Field is missing. Data should survive.
+    unset($entity->{$this->field_name});
+    field_attach_update($entity);
+    $count = db_select($this->table)
+      ->countQuery()
+      ->execute()
+      ->fetchField();
+    $this->assertEqual($count, 1, 'Missing field leaves data in table');
+
     // Update: Field is NULL. Data should be wiped.
-    $entity->getBCEntity()->{$this->field_name} = NULL;
+    $entity->{$this->field_name} = NULL;
     field_attach_update($entity);
     $count = db_select($this->table)
       ->countQuery()
@@ -311,7 +301,7 @@ function testFieldAttachSaveMissingData() {
     $this->assertEqual($count, 1, 'Field translation in an unavailable language saved.');
 
     // Again add some real data.
-    $entity->{$this->field_name}->value = 1;
+    $entity->{$this->field_name}[$langcode] = array(0 => array('value' => 1));
     field_attach_insert($entity);
     $count = db_select($this->table)
       ->countQuery()
@@ -321,8 +311,8 @@ function testFieldAttachSaveMissingData() {
 
     // Update: Field translation is missing but field is not empty. Translation
     // data should survive.
-    $entity->getTranslation($unavailable_langcode)->{$this->field_name} = mt_rand(1, 127);
-    unset($entity->{$this->field_name});
+    $entity->{$this->field_name}[$unavailable_langcode] = array(mt_rand(1, 127));
+    unset($entity->{$this->field_name}[$langcode]);
     field_attach_update($entity);
     $count = db_select($this->table)
       ->countQuery()
@@ -332,7 +322,7 @@ function testFieldAttachSaveMissingData() {
 
     // Update: Field translation is NULL but field is not empty. Translation
     // data should be wiped.
-    $entity->getBCEntity()->{$this->field_name}[Language::LANGCODE_NOT_SPECIFIED] = NULL;
+    $entity->{$this->field_name}[$langcode] = NULL;
     field_attach_update($entity);
     $count = db_select($this->table)
       ->countQuery()
@@ -345,7 +335,6 @@ function testFieldAttachSaveMissingData() {
    * Test trying to update a field with data.
    */
   function testUpdateFieldSchemaWithData() {
-    $entity_type = 'entity_test_rev';
     // Create a decimal 5.2 field and add some data.
     $field = entity_create('field_entity', array(
       'field_name' => 'decimal52',
@@ -355,15 +344,12 @@ function testUpdateFieldSchemaWithData() {
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => 'decimal52',
-      'entity_type' => $entity_type,
-      'bundle' => $entity_type,
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     ));
     $instance->save();
-    $entity = entity_create($entity_type, array(
-      'id' => 0,
-      'revision_id' => 0,
-    ));
-    $entity->decimal52->value = '1.235';
+    $entity = field_test_create_entity(0, 0, $instance->bundle);
+    $entity->decimal52[Language::LANGCODE_NOT_SPECIFIED][0]['value'] = '1.235';
     $entity->save();
 
     // Attempt to update the field in a way that would work without data.
@@ -412,15 +398,14 @@ function testFieldUpdateFailure() {
   function testFieldUpdateIndexesWithData() {
     // Create a decimal field.
     $field_name = 'testfield';
-    $entity_type = 'entity_test_rev';
     $field = entity_create('field_entity', array(
       'field_name' => $field_name,
       'type' => 'text'));
     $field->save();
     $instance = entity_create('field_instance', array(
       'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $entity_type,
+      'entity_type' => 'test_entity',
+      'bundle' => 'test_bundle',
     ));
     $instance->save();
     $tables = array(_field_sql_storage_tablename($field), _field_sql_storage_revision_tablename($field));
@@ -432,12 +417,8 @@ function testFieldUpdateIndexesWithData() {
     }
 
     // Add data so the table cannot be dropped.
-    $entity = entity_create($entity_type, array(
-      'id' => 1,
-      'revision_id' => 1,
-    ));
-    $entity->$field_name->value = 'field data';
-    $entity->enforceIsNew();
+    $entity = field_test_create_entity(1, 1, $instance->bundle);
+    $entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['value'] = 'field data';
     $entity->save();
 
     // Add an index.
@@ -456,12 +437,9 @@ function testFieldUpdateIndexesWithData() {
     }
 
     // Verify that the tables were not dropped.
-    $entity = entity_create($entity_type, array(
-      'id' => 1,
-      'revision_id' => 1,
-    ));
-    field_attach_load($entity_type, array(1 => $entity));
-    $this->assertEqual($entity->$field_name->value, 'field data', t("Index changes performed without dropping the tables"));
+    $entity = field_test_create_entity(1, 1, $instance->bundle);
+    field_attach_load('test_entity', array(1 => $entity));
+    $this->assertEqual($entity->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['value'], 'field data', t("Index changes performed without dropping the tables"));
   }
 
   /**
diff --git a/core/modules/field_ui/field_ui.admin.inc b/core/modules/field_ui/field_ui.admin.inc
index 624f124..4f429cc 100644
--- a/core/modules/field_ui/field_ui.admin.inc
+++ b/core/modules/field_ui/field_ui.admin.inc
@@ -6,6 +6,58 @@
  */
 
 /**
+ * Page callback: Lists all defined fields for quick reference.
+ *
+ * @see field_ui_menu()
+ */
+function field_ui_fields_list() {
+  $instances = field_info_instances();
+  $field_types = field_info_field_types();
+  $bundles = entity_get_bundles();
+  $entity_manager = Drupal::entityManager();
+
+  $modules = system_rebuild_module_data();
+
+  $header = array(
+    t('Field name'),
+    array('data' => t('Field type'), 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)),
+    t('Used in'),
+  );
+  $rows = array();
+  foreach ($instances as $entity_type => $type_bundles) {
+    foreach ($type_bundles as $bundle => $bundle_instances) {
+      foreach ($bundle_instances as $field_name => $instance) {
+        $field = field_info_field($field_name);
+
+        // Initialize the row if we encounter the field for the first time.
+        if (!isset($rows[$field_name])) {
+          $rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
+          $rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
+          $module_name = $field_types[$field['type']]['module'];
+          $rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
+        }
+
+        // Add the current instance.
+        $admin_path = $entity_manager->getAdminPath($entity_type, $bundle);
+        $rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
+      }
+    }
+  }
+  foreach ($rows as $field_name => $cell) {
+    $rows[$field_name]['data'][2] = implode(', ', $cell['data'][2]);
+  }
+  if (empty($rows)) {
+    $output = t('No fields have been defined yet.');
+  }
+  else {
+    // Sort rows by field name.
+    ksort($rows);
+    $output = theme('table', array('header' => $header, 'rows' => $rows));
+  }
+  return $output;
+}
+
+/**
  * Returns HTML for Field UI overview tables.
  *
  * @param $variables
diff --git a/core/modules/field_ui/field_ui.module b/core/modules/field_ui/field_ui.module
index 17e8ad0..7f617ae 100644
--- a/core/modules/field_ui/field_ui.module
+++ b/core/modules/field_ui/field_ui.module
@@ -56,8 +56,10 @@ function field_ui_menu() {
   $items['admin/reports/fields'] = array(
     'title' => 'Field list',
     'description' => 'Overview of fields on all entity types.',
-    'route_name' => 'field_list',
+    'page callback' => 'field_ui_fields_list',
+    'access arguments' => array('administer content types'),
     'type' => MENU_NORMAL_ITEM,
+    'file' => 'field_ui.admin.inc',
   );
   $items['admin/reports/fields/list'] = array(
     'title' => 'Entities',
@@ -236,7 +238,6 @@ function field_ui_element_info() {
  */
 function field_ui_entity_info(&$entity_info) {
   $entity_info['field_instance']['controllers']['form']['delete'] = 'Drupal\field_ui\Form\FieldDeleteForm';
-  $entity_info['field_entity']['controllers']['list'] = 'Drupal\field_ui\FieldListController';
 }
 
 /**
@@ -267,11 +268,13 @@ function field_ui_entity_bundle_rename($entity_type, $bundle_old, $bundle_new) {
  */
 function field_ui_form_node_type_form_alter(&$form, $form_state) {
   // We want to display the button only on add page.
-  if ($form_state['controller']->getEntity()->isNew()) {
-    $form['actions']['save_continue'] = $form['actions']['submit'];
-    $form['actions']['save_continue']['#value'] = t('Save and manage fields');
-    $form['actions']['save_continue']['#weight'] = $form['actions']['save_continue']['#weight'] + 5;
-    $form['actions']['save_continue']['#submit'][] = 'field_ui_form_node_type_form_submit';
+  if (empty($form['#node_type']->type)) {
+    $form['actions']['save_continue'] = array(
+      '#type' => 'submit',
+      '#value' => t('Save and manage fields'),
+      '#weight' => 45,
+    );
+    $form['#submit'][] = 'field_ui_form_node_type_form_submit';
   }
 }
 
diff --git a/core/modules/field_ui/field_ui.routing.yml b/core/modules/field_ui/field_ui.routing.yml
deleted file mode 100644
index 946d60e..0000000
--- a/core/modules/field_ui/field_ui.routing.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-field_list:
-  pattern: 'admin/reports/fields'
-  defaults:
-    _entity_list: 'field_entity'
-  requirements:
-    _permission: 'administer content types'
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php b/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php
deleted file mode 100644
index cd3d640..0000000
--- a/core/modules/field_ui/lib/Drupal/field_ui/FieldListController.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\field_ui\FieldListController.
- */
-
-namespace Drupal\field_ui;
-
-use Drupal\Core\Config\Entity\ConfigEntityListController;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityManager;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\field\FieldInfo;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-
-/**
- * Provides a listing of fields.
- */
-class FieldListController extends ConfigEntityListController {
-
-  /**
-   * An array of information about field types.
-   *
-   * @var array
-   */
-  protected $fieldTypes;
-
-  /**
-   * An array of field data.
-   *
-   * @var array
-   */
-  protected $fieldInfo;
-
-  /**
-   * The entity manager.
-   *
-   * @var \Drupal\Core\Entity\EntityManager
-   */
-  protected $entityManager;
-
-  /**
-   * An array of entity bundle information.
-   *
-   * @var array
-   */
-  protected $bundles;
-
-  /**
-   * Constructs a new EntityListController object.
-   *
-   * @param string $entity_type
-   *   The type of entity to be listed.
-   * @param array $entity_info
-   *   An array of entity info for the entity type.
-   * @param \Drupal\Core\Entity\EntityManager $entity_manager
-   *   The entity manager.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler to invoke hooks on.
-   * @param \Drupal\field\FieldInfo $field_info
-   *   The field info service.
-   */
-  public function __construct($entity_type, array $entity_info, EntityManager $entity_manager, ModuleHandlerInterface $module_handler, FieldInfo $field_info) {
-    parent::__construct($entity_type, $entity_info, $entity_manager->getStorageController($entity_type), $module_handler);
-
-    $this->fieldTypes = field_info_field_types();
-    $this->fieldInfo = $field_info->getFieldMap();
-    $this->entityManager = $entity_manager;
-    $this->bundles = entity_get_bundles();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
-    return new static(
-      $entity_type,
-      $entity_info,
-      $container->get('plugin.manager.entity'),
-      $container->get('module_handler'),
-      $container->get('field.info')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildHeader() {
-    $row['id'] = t('Field name');
-    $row['type'] = array(
-      'data' => t('Field type'),
-      'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
-    );
-    $row['usage'] = t('Used in');
-    return $row;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildRow(EntityInterface $entity) {
-    if ($entity->locked) {
-      $row['class'] = array('menu-disabled');
-      $row['data']['id'] =  t('@field_name (Locked)', array('@field_name' => $entity->id()));
-    }
-    else {
-      $row['data']['id'] = $entity->id();
-    }
-
-    $field_type = $this->fieldTypes[$entity->getFieldType()];
-    $row['data']['type'] = t('@type (module: @module)', array('@type' => $field_type['label'], '@module' => $field_type['module']));
-
-    $usage = array();
-    foreach($this->fieldInfo[$entity->id()]['bundles'] as $entity_type => $field_bundles) {
-      foreach($field_bundles as $bundle) {
-        $admin_path = $this->entityManager->getAdminPath($entity_type, $bundle);
-        $usage[] = $admin_path ? l($this->bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $this->bundles[$entity_type][$bundle]['label'];
-      }
-    }
-    $row['data']['usage'] = implode(', ', $usage);
-    return $row;
-  }
-
-}
diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
index 56370ad..b978964 100644
--- a/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
+++ b/core/modules/field_ui/lib/Drupal/field_ui/Tests/ManageFieldsTest.php
@@ -72,7 +72,6 @@ function testCRUDFields() {
     $this->updateField();
     $this->addExistingField();
     $this->cardinalitySettings();
-    $this->fieldListAdminPage();
   }
 
   /**
@@ -596,13 +595,4 @@ function testHelpDescriptions() {
     $this->assertRaw('<strong>Test with an upload field.</strong>');
     $this->assertRaw('<em>Test with a non upload field.</em>');
   }
-
-  /**
-   * Tests that the field list administration page operates correctly.
-   */
-  function fieldListAdminPage() {
-    $this->drupalGet('admin/reports/fields');
-    $this->assertText($this->field_name, 'Field name is displayed in field list.');
-    $this->assertTrue($this->assertLinkByHref('admin/structure/types/manage/' . $this->type . '/fields'), 'Link to content type using field is displayed in field list.');
-  }
 }
diff --git a/core/modules/file/file.api.php b/core/modules/file/file.api.php
index c713214..49d9af8 100644
--- a/core/modules/file/file.api.php
+++ b/core/modules/file/file.api.php
@@ -38,7 +38,7 @@ function hook_file_load($files) {
   $result = db_query('SELECT * FROM {upload} u WHERE u.fid IN (:fids)', array(':fids' => array_keys($files)))->fetchAll(PDO::FETCH_ASSOC);
   foreach ($result as $record) {
     foreach ($record as $key => $value) {
-      $files[$record['target_id']]->$key = $value;
+      $files[$record['fid']]->$key = $value;
     }
   }
 }
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index 3305a00..289c67f 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -189,7 +189,7 @@ function _file_generic_settings_file_directory_validate($element, &$form_state)
 function file_field_insert(EntityInterface $entity, $field, $instance, $langcode, &$items) {
   // Add a new usage of each uploaded file.
   foreach ($items as $item) {
-    file_usage()->add(file_load($item['target_id']), 'file', $entity->entityType(), $entity->id());
+    file_usage()->add(file_load($item['fid']), 'file', $entity->entityType(), $entity->id());
   }
 }
 
@@ -203,7 +203,7 @@ function file_field_update(EntityInterface $entity, $field, $instance, $langcode
   // deletion of previous file usages are necessary.
   if (!empty($entity->original) && $entity->getRevisionId() != $entity->original->getRevisionId()) {
     foreach ($items as $item) {
-      file_usage()->add(file_load($item['target_id']), 'file', $entity->entityType(), $entity->id());
+      file_usage()->add(file_load($item['fid']), 'file', $entity->entityType(), $entity->id());
     }
     return;
   }
@@ -211,7 +211,7 @@ function file_field_update(EntityInterface $entity, $field, $instance, $langcode
   // Build a display of the current FIDs.
   $current_fids = array();
   foreach ($items as $item) {
-    $current_fids[] = $item['target_id'];
+    $current_fids[] = $item['fid'];
   }
 
   // Compare the original field values with the ones that are being saved.
@@ -219,18 +219,18 @@ function file_field_update(EntityInterface $entity, $field, $instance, $langcode
   $original_fids = array();
   if (!empty($original->{$field['field_name']}[$langcode])) {
     foreach ($original->{$field['field_name']}[$langcode] as $original_item) {
-      $original_fids[] = $original_item['target_id'];
-      if (isset($original_item['target_id']) && !in_array($original_item['target_id'], $current_fids)) {
+      $original_fids[] = $original_item['fid'];
+      if (isset($original_item['fid']) && !in_array($original_item['fid'], $current_fids)) {
         // Decrement the file usage count by 1.
-        file_usage()->delete(file_load($original_item['target_id']), 'file', $entity->entityType(), $entity->id());
+        file_usage()->delete(file_load($original_item['fid']), 'file', $entity->entityType(), $entity->id());
       }
     }
   }
 
   // Add new usage entries for newly added files.
   foreach ($items as $item) {
-    if (!in_array($item['target_id'], $original_fids)) {
-      file_usage()->add(file_load($item['target_id']), 'file', $entity->entityType(), $entity->id());
+    if (!in_array($item['fid'], $original_fids)) {
+      file_usage()->add(file_load($item['fid']), 'file', $entity->entityType(), $entity->id());
     }
   }
 }
@@ -241,7 +241,7 @@ function file_field_update(EntityInterface $entity, $field, $instance, $langcode
 function file_field_delete(EntityInterface $entity, $field, $instance, $langcode, &$items) {
   // Delete all file usages within this entity.
   foreach ($items as $delta => $item) {
-    file_usage()->delete(file_load($item['target_id']), 'file', $entity->entityType(), $entity->id(), 0);
+    file_usage()->delete(file_load($item['fid']), 'file', $entity->entityType(), $entity->id(), 0);
   }
 }
 
@@ -251,7 +251,7 @@ function file_field_delete(EntityInterface $entity, $field, $instance, $langcode
 function file_field_delete_revision(EntityInterface $entity, $field, $instance, $langcode, &$items) {
   foreach ($items as $delta => $item) {
     // Decrement the file usage count by 1.
-    file_usage()->delete(file_load($item['target_id']), 'file', $entity->entityType(), $entity->id());
+    file_usage()->delete(file_load($item['fid']), 'file', $entity->entityType(), $entity->id());
   }
 }
 
@@ -259,7 +259,7 @@ function file_field_delete_revision(EntityInterface $entity, $field, $instance,
  * Implements hook_field_is_empty().
  */
 function file_field_is_empty($item, $field_type) {
-  return empty($item['target_id']);
+  return empty($item['fid']);
 }
 
 /**
diff --git a/core/modules/file/file.install b/core/modules/file/file.install
index 1f31e43..0c97f82 100644
--- a/core/modules/file/file.install
+++ b/core/modules/file/file.install
@@ -5,8 +5,6 @@
  * Install, update and uninstall functions for File module.
  */
 
-use Drupal\field\Plugin\Core\Entity\Field;
-
 /**
  * Implements hook_schema().
  */
@@ -156,10 +154,10 @@ function file_schema() {
 function file_field_schema($field) {
   return array(
     'columns' => array(
-      'target_id' => array(
-        'description' => 'The ID of the target entity.',
+      'fid' => array(
+        'description' => 'The {file_managed}.fid being referenced in this field.',
         'type' => 'int',
-        'not null' => TRUE,
+        'not null' => FALSE,
         'unsigned' => TRUE,
       ),
       'display' => array(
@@ -177,12 +175,12 @@ function file_field_schema($field) {
       ),
     ),
     'indexes' => array(
-      'target_id' => array('target_id'),
+      'fid' => array('fid'),
     ),
     'foreign keys' => array(
-      'target_id' => array(
+      'fid' => array(
         'table' => 'file_managed',
-        'columns' => array('target_id' => 'fid'),
+        'columns' => array('fid' => 'fid'),
       ),
     ),
   );
@@ -245,12 +243,6 @@ function file_update_dependencies() {
   $dependencies['field'][8003] = array(
     'file' => 8001,
   );
-
-  // Convert the 'fid' column of file fields to 'target_id' after fields and
-  // instances have been moved to the config system.
-  $dependencies['file'][8003] = array(
-    'field' => 8003,
-  );
   return $dependencies;
 }
 
@@ -296,46 +288,3 @@ function file_update_8002() {
     db_change_field('file_usage', 'module', 'module', $spec);
   }
 }
-
-/**
- * Update file field tables to use target_id instead of fid.
- */
-function file_update_8003() {
-  foreach (config_get_storage_names_with_prefix('field.field.') as $config_name) {
-    $field_config = config($config_name);
-    // Only update file fields that use the default SQL storage.
-    if (in_array($field_config->get('type'), array('file', 'image')) && $field_config->get('storage.type') == 'field_sql_storage') {
-      $field = new Field($field_config->get());
-
-      $tables = array(
-        _field_sql_storage_tablename($field),
-        _field_sql_storage_revision_tablename($field),
-      );
-
-      foreach ($tables as $table_name) {
-        // Skip fields which were created during the upgrade process.
-        if (!db_field_exists($table_name, $field->id() . '_fid')) {
-          continue 2;
-        }
-
-        db_change_field($table_name, $field->id() . '_fid', $field->id() . '_target_id', array(
-          'description' => 'The ID of the target entity.',
-          'type' => 'int',
-          'unsigned' => TRUE,
-          'not null' => TRUE,
-        ));
-
-        // Change the index.
-        db_drop_index($table_name, $field->id() . '_fid');
-        db_add_index($table_name, $field->id() . '_target_id', array($field->id() . '_target_id'));
-      }
-
-      // Update the indexes in field config as well.
-      $indexes = $field_config->get('indexes');
-      unset($indexes['fid']);
-      $indexes['target_id'] = array('target_id');
-      $field_config->set('indexes', $indexes);
-      $field_config->save();
-    }
-  }
-}
diff --git a/core/modules/file/file.views.inc b/core/modules/file/file.views.inc
index 5c2743f..c9e271f 100644
--- a/core/modules/file/file.views.inc
+++ b/core/modules/file/file.views.inc
@@ -455,11 +455,11 @@ function file_field_views_data($field) {
   $data = field_views_field_default_views_data($field);
   foreach ($data as $table_name => $table_data) {
     // Add the relationship only on the fid field.
-    $data[$table_name][$field['field_name'] . '_target_id']['relationship'] = array(
+    $data[$table_name][$field['field_name'] . '_fid']['relationship'] = array(
       'id' => 'standard',
       'base' => 'file_managed',
       'entity type' => 'file',
-      'base field' => 'target_id',
+      'base field' => 'fid',
       'label' => t('file from !field_name', array('!field_name' => $field['field_name'])),
     );
   }
@@ -489,7 +489,7 @@ function file_field_views_data_views_data_alter(&$data, $field) {
       'id' => 'entity_reverse',
       'field_name' => $field['field_name'],
       'field table' => _field_sql_storage_tablename($field),
-      'field field' => $field['field_name'] . '_target_id',
+      'field field' => $field['field_name'] . '_fid',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
       'label' => t('!field_name', array('!field_name' => $field['field_name'])),
diff --git a/core/modules/file/lib/Drupal/file/Plugin/field/formatter/FileFormatterBase.php b/core/modules/file/lib/Drupal/file/Plugin/field/formatter/FileFormatterBase.php
index ccf28d3..358648b 100644
--- a/core/modules/file/lib/Drupal/file/Plugin/field/formatter/FileFormatterBase.php
+++ b/core/modules/file/lib/Drupal/file/Plugin/field/formatter/FileFormatterBase.php
@@ -22,9 +22,9 @@ public function prepareView(array $entities, $langcode, array &$items) {
     $fids = array();
     foreach ($entities as $id => $entity) {
       foreach ($items[$id] as $delta => $item) {
-        if ($this->isDisplayed($item) && !empty($item['target_id'])) {
+        if ($this->isDisplayed($item) && !empty($item['fid'])) {
           // Load the files from the files table.
-          $fids[] = $item['target_id'];
+          $fids[] = $item['fid'];
         }
       }
     }
@@ -35,8 +35,8 @@ public function prepareView(array $entities, $langcode, array &$items) {
       foreach ($entities as $id => $entity) {
         foreach ($items[$id] as $delta => $item) {
           // If the file does not exist, mark the entire item as empty.
-          if (!empty($item['target_id'])) {
-            $items[$id][$delta]['entity'] = isset($files[$item['target_id']]) ? $files[$item['target_id']] : NULL;
+          if (!empty($item['fid'])) {
+            $items[$id][$delta]['entity'] = isset($files[$item['fid']]) ? $files[$item['fid']] : NULL;
           }
         }
       }
diff --git a/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php b/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php
index c63df17..4603288 100644
--- a/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php
+++ b/core/modules/file/lib/Drupal/file/Plugin/field/widget/FileWidget.php
@@ -209,8 +209,8 @@ public function formElement(array $items, $delta, array $element, $langcode, arr
 
     // Field stores FID value in a single mode, so we need to transform it for
     // form element to recognize it correctly.
-    if (!isset($items[$delta]['fids']) && isset($items[$delta]['target_id'])) {
-      $items[$delta]['fids'][0] = $items[$delta]['target_id'];
+    if (!isset($items[$delta]['fids']) && isset($items[$delta]['fid'])) {
+      $items[$delta]['fids'][0] = $items[$delta]['fid'];
     }
     $element['#default_value'] = !empty($items[$delta]) ? $items[$delta] : $defaults;
 
@@ -237,7 +237,7 @@ public function massageFormValues(array $values, array $form, array &$form_state
     foreach ($values as &$value) {
       foreach ($value['fids'] as $fid) {
         $new_value = $value;
-        $new_value['target_id'] = $fid;
+        $new_value['fid'] = $fid;
         unset($new_value['fids']);
         $new_values[] = $new_value;
       }
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php
index 29ba4ef..8d73392 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldDisplayTest.php
@@ -60,7 +60,7 @@ function testNodeDisplay() {
 
     // Check that the default formatter is displaying with the file name.
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $default_output = theme('file_link', array('file' => $node_file));
     $this->assertRaw($default_output, 'Default formatter displaying correctly on full node view.');
 
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php
index f2c45b6..9055560 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldPathTest.php
@@ -35,7 +35,7 @@ function testUploadPath() {
 
     // Check that the file was uploaded to the file root.
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertPathMatch('public://' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri())));
 
     // Change the path to contain multiple subdirectories.
@@ -46,7 +46,7 @@ function testUploadPath() {
 
     // Check that the file was uploaded into the subdirectory.
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'], TRUE);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'], TRUE);
     $this->assertPathMatch('public://foo/bar/baz/' . $test_file->getFilename(), $node_file->getFileUri(), format_string('The file %file was uploaded to the correct path.', array('%file' => $node_file->getFileUri())));
 
     // Check the path when used with tokens.
@@ -58,7 +58,7 @@ function testUploadPath() {
 
     // Check that the file was uploaded into the subdirectory.
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     // Do token replacement using the same user which uploaded the file, not
     // the user running the test case.
     $data = array('user' => $this->admin_user);
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php
index 7847a16..a3b86ea 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRSSContentTest.php
@@ -67,7 +67,7 @@ function testFileFieldRSSContent() {
 
     // Get the uploaded file from the node.
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
 
     // Check that the RSS enclosure appears in the RSS feed.
     $this->drupalGet('rss.xml');
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
index 84e23c3..0a5ffa4 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldRevisionTest.php
@@ -47,7 +47,7 @@ function testRevisions() {
 
     // Check that the file exists on disk and in the database.
     $node = node_load($nid, TRUE);
-    $node_file_r1 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file_r1 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $node_vid_r1 = $node->vid;
     $this->assertFileExists($node_file_r1, 'New file saved to disk on node creation.');
     $this->assertFileEntryExists($node_file_r1, 'File entry exists in database on node creation.');
@@ -56,7 +56,7 @@ function testRevisions() {
     // Upload another file to the same node in a new revision.
     $this->replaceNodeFile($test_file, $field_name, $nid);
     $node = node_load($nid, TRUE);
-    $node_file_r2 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file_r2 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $node_vid_r2 = $node->vid;
     $this->assertFileExists($node_file_r2, 'Replacement file exists on disk after creating new revision.');
     $this->assertFileEntryExists($node_file_r2, 'Replacement file entry exists in database after creating new revision.');
@@ -64,7 +64,7 @@ function testRevisions() {
 
     // Check that the original file is still in place on the first revision.
     $node = node_revision_load($node_vid_r1);
-    $current_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $current_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertEqual($node_file_r1->id(), $current_file->id(), 'Original file still in place after replacing file in new revision.');
     $this->assertFileExists($node_file_r1, 'Original file still in place after replacing file in new revision.');
     $this->assertFileEntryExists($node_file_r1, 'Original file entry still in place after replacing file in new revision');
@@ -74,7 +74,7 @@ function testRevisions() {
     // Check that the file is still the same as the previous revision.
     $this->drupalPost('node/' . $nid . '/edit', array('revision' => '1'), t('Save and keep published'));
     $node = node_load($nid, TRUE);
-    $node_file_r3 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file_r3 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $node_vid_r3 = $node->vid;
     $this->assertEqual($node_file_r2->id(), $node_file_r3->id(), 'Previous revision file still in place after creating a new revision without a new file.');
     $this->assertFileIsPermanent($node_file_r3, 'New revision file is permanent.');
@@ -82,7 +82,7 @@ function testRevisions() {
     // Revert to the first revision and check that the original file is active.
     $this->drupalPost('node/' . $nid . '/revisions/' . $node_vid_r1 . '/revert', array(), t('Revert'));
     $node = node_load($nid, TRUE);
-    $node_file_r4 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file_r4 = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $node_vid_r4 = $node->vid;
     $this->assertEqual($node_file_r1->id(), $node_file_r4->id(), 'Original revision file still in place after reverting to the original revision.');
     $this->assertFileIsPermanent($node_file_r4, 'Original revision file still permanent after reverting to the original revision.');
@@ -96,7 +96,7 @@ function testRevisions() {
 
     // Attach the second file to a user.
     $user = $this->drupalCreateUser();
-    $user->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'] = $node_file_r3->id();
+    $user->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'] = $node_file_r3->id();
     $user->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['display'] = 1;
     $user->save();
     $this->drupalGet('user/' . $user->uid . '/edit');
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
index a7cf1e5..19029c4 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldValidateTest.php
@@ -47,7 +47,7 @@ function testRequired() {
 
     $node = node_load($nid, TRUE);
 
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($node_file, 'File exists after uploading to the required field.');
     $this->assertFileEntryExists($node_file, 'File entry exists after uploading to the required field.');
 
@@ -63,7 +63,7 @@ function testRequired() {
     // Create a new node with the uploaded file into the multivalue field.
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($node_file, 'File exists after uploading to the required multiple value field.');
     $this->assertFileEntryExists($node_file, 'File entry exists after uploading to the required multiple value field.');
   }
@@ -93,7 +93,7 @@ function testFileMaxSize() {
       // Create a new node with the small file, which should pass.
       $nid = $this->uploadNodeFile($small_file, $field_name, $type_name);
       $node = node_load($nid, TRUE);
-      $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+      $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
       $this->assertFileExists($node_file, format_string('File exists after uploading a file (%filesize) under the max limit (%maxsize).', array('%filesize' => format_size($small_file->getSize()), '%maxsize' => $max_filesize)));
       $this->assertFileEntryExists($node_file, format_string('File entry exists after uploading a file (%filesize) under the max limit (%maxsize).', array('%filesize' => format_size($small_file->getSize()), '%maxsize' => $max_filesize)));
 
@@ -109,7 +109,7 @@ function testFileMaxSize() {
     // Upload the big file successfully.
     $nid = $this->uploadNodeFile($large_file, $field_name, $type_name);
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($node_file, format_string('File exists after uploading a file (%filesize) with no max limit.', array('%filesize' => format_size($large_file->getSize()))));
     $this->assertFileEntryExists($node_file, format_string('File entry exists after uploading a file (%filesize) with no max limit.', array('%filesize' => format_size($large_file->getSize()))));
   }
@@ -131,7 +131,7 @@ function testFileExtension() {
     // Check that the file can be uploaded with no extension checking.
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($node_file, 'File exists after uploading a file with no extension checking.');
     $this->assertFileEntryExists($node_file, 'File entry exists after uploading a file with no extension checking.');
 
@@ -149,7 +149,7 @@ function testFileExtension() {
     // Check that the file can be uploaded with extension checking.
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($node_file, 'File exists after uploading a file with extension checking.');
     $this->assertFileEntryExists($node_file, 'File entry exists after uploading a file with extension checking.');
   }
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
index 2389423..6a097c6 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
@@ -46,7 +46,7 @@ function testSingleValuedWidget() {
       //   does not yet support file uploads.
       $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
       $node = node_load($nid, TRUE);
-      $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+      $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
       $this->assertFileExists($node_file, 'New file saved to disk on node creation.');
 
       // Ensure the file can be downloaded.
@@ -79,7 +79,7 @@ function testSingleValuedWidget() {
       // Save the node and ensure it does not have the file.
       $this->drupalPost(NULL, array(), t('Save and keep published'));
       $node = node_load($nid, TRUE);
-      $this->assertTrue(empty($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']), 'File was successfully removed from the node.');
+      $this->assertTrue(empty($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']), 'File was successfully removed from the node.');
     }
   }
 
@@ -196,7 +196,7 @@ function testMultiValuedWidget() {
       preg_match('/node\/([0-9]+)/', $this->getUrl(), $matches);
       $nid = $matches[1];
       $node = node_load($nid, TRUE);
-      $this->assertTrue(empty($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']), 'Node was successfully saved without any files.');
+      $this->assertTrue(empty($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']), 'Node was successfully saved without any files.');
     }
   }
 
@@ -216,7 +216,7 @@ function testPrivateFileSetting() {
     $this->drupalPost("admin/structure/types/manage/$type_name/fields/$instance->id/field", $edit, t('Save field settings'));
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name);
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertFileExists($node_file, 'New file saved to disk on node creation.');
 
     // Ensure the private file is available to the user who uploaded it.
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php b/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php
index fd00c11..def3a48 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileItemTest.php
@@ -67,7 +67,7 @@ public function setUp() {
   public function testFileItem() {
     // Create a test entity with the
     $entity = entity_create('entity_test', array());
-    $entity->file_test->target_id = $this->file->id();
+    $entity->file_test->fid = $this->file->id();
     $entity->file_test->display = 1;
     $entity->file_test->description = $description = $this->randomName();
     $entity->name->value = $this->randomName();
@@ -76,7 +76,7 @@ public function testFileItem() {
     $entity = entity_load('entity_test', $entity->id());
     $this->assertTrue($entity->file_test instanceof FieldInterface, 'Field implements interface.');
     $this->assertTrue($entity->file_test[0] instanceof FieldItemInterface, 'Field item implements interface.');
-    $this->assertEqual($entity->file_test->target_id, $this->file->id());
+    $this->assertEqual($entity->file_test->fid, $this->file->id());
     $this->assertEqual($entity->file_test->display, 1);
     $this->assertEqual($entity->file_test->description, $description);
     $this->assertEqual($entity->file_test->entity->getFileUri(), $this->file->getFileUri());
@@ -90,7 +90,7 @@ public function testFileItem() {
     ));
     $file2->save();
 
-    $entity->file_test->target_id = $file2->id();
+    $entity->file_test->fid = $file2->id();
     $this->assertEqual($entity->file_test->entity->id(), $file2->id());
     $this->assertEqual($entity->file_test->entity->getFileUri(), $file2->getFileUri());
   }
diff --git a/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php b/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php
index 1b8a82f..b541953 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FilePrivateTest.php
@@ -50,7 +50,7 @@ function testPrivateFile() {
     $test_file = $this->getTestFile('text');
     $nid = $this->uploadNodeFile($test_file, $field_name, $type_name, TRUE, array('private' => TRUE));
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     // Ensure the file can be downloaded.
     $this->drupalGet(file_create_url($node_file->getFileUri()));
     $this->assertResponse(200, 'Confirmed that the generated URL is correct by downloading the shipped file.');
@@ -62,7 +62,7 @@ function testPrivateFile() {
     $this->drupalLogin($this->admin_user);
     $nid = $this->uploadNodeFile($test_file, $no_access_field_name, $type_name, TRUE, array('private' => TRUE));
     $node = node_load($nid, TRUE);
-    $node_file = file_load($node->{$no_access_field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $node_file = file_load($node->{$no_access_field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     // Ensure the file cannot be downloaded.
     $this->drupalGet(file_create_url($node_file->getFileUri()));
     $this->assertResponse(403, 'Confirmed that access is denied for the file without view field access permission.');
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php b/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php
index c154332..9787554 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileTokenReplaceTest.php
@@ -47,7 +47,7 @@ function testFileTokenReplacement() {
 
     // Load the node and the file.
     $node = node_load($nid, TRUE);
-    $file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $file = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
 
     // Generate and test sanitized tokens.
     $tests = array();
diff --git a/core/modules/file/lib/Drupal/file/Type/FileItem.php b/core/modules/file/lib/Drupal/file/Type/FileItem.php
index 9b2cc4c..34e5753 100644
--- a/core/modules/file/lib/Drupal/file/Type/FileItem.php
+++ b/core/modules/file/lib/Drupal/file/Type/FileItem.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\file\Type;
 
-use Drupal\field\Plugin\Type\FieldType\ConfigEntityReferenceItemBase;
+use Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem;
 
 /**
  * Defines the 'file_field' entity field item.
  */
-class FileItem extends ConfigEntityReferenceItemBase {
+class FileItem extends LegacyConfigFieldItem {
 
   /**
    * Property definitions of the contained properties.
@@ -24,14 +24,14 @@ class FileItem extends ConfigEntityReferenceItemBase {
   static $propertyDefinitions;
 
   /**
-   * {@inheritdoc}
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
-    $this->definition['settings']['target_type'] = 'file';
-
     if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions = parent::getPropertyDefinitions();
-
+      static::$propertyDefinitions['fid'] = array(
+        'type' => 'integer',
+        'label' => t('Referenced file id.'),
+      );
       static::$propertyDefinitions['display'] = array(
         'type' => 'boolean',
         'label' => t('Flag to control whether this file should be displayed when viewing content.'),
@@ -40,8 +40,39 @@ public function getPropertyDefinitions() {
         'type' => 'string',
         'label' => t('A description of the file.'),
       );
+      static::$propertyDefinitions['entity'] = array(
+        'type' => 'entity',
+        'constraints' => array(
+          'EntityType' => 'file',
+        ),
+        'label' => t('File'),
+        'description' => t('The referenced file'),
+        // The entity object is computed out of the fid.
+        'computed' => TRUE,
+        'read-only' => FALSE,
+        'settings' => array('id source' => 'fid'),
+      );
     }
     return static::$propertyDefinitions;
   }
 
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
+   */
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as value of the entity property, if no array is
+    // given as this handles entity IDs and objects.
+    if (isset($values) && !is_array($values)) {
+      // Directly update the property instead of invoking the parent, so that
+      // the entity property can take care of updating the ID property.
+      $this->properties['entity']->setValue($values, $notify);
+    }
+    else {
+      // Make sure that the 'entity' property gets set as 'target_id'.
+      if (isset($values['fid']) && !isset($values['entity'])) {
+        $values['entity'] = $values['fid'];
+      }
+      parent::setValue($values, $notify);
+    }
+  }
 }
diff --git a/core/modules/forum/config/node.type.forum.yml b/core/modules/forum/config/node.type.forum.yml
deleted file mode 100644
index 71dce86..0000000
--- a/core/modules/forum/config/node.type.forum.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-type: forum
-uuid: c14b392d-0889-46bd-889e-a239e8b6cd89
-name: 'Forum topic'
-description: 'A <em>forum topic</em> starts a new discussion thread within a forum.'
-help: ''
-has_title: '1'
-title_label: Subject
-settings:
-  node:
-    preview: '1'
-    options:
-      status: status
-      # Not promoted to front page.
-      promote: '0'
-      sticky: '0'
-      revision: '0'
-    submitted: '1'
-status: '1'
-langcode: en
diff --git a/core/modules/forum/config/rdf.mapping.node.forum.yml b/core/modules/forum/config/rdf.mapping.node.forum.yml
index 1b6d1c7..ea86bc5 100644
--- a/core/modules/forum/config/rdf.mapping.node.forum.yml
+++ b/core/modules/forum/config/rdf.mapping.node.forum.yml
@@ -2,10 +2,27 @@ id: node.forum
 targetEntityType: node
 bundle: forum
 types:
-  - 'sioc:Post'
-  - 'sioct:BoardPost'
+  - 'schema:Discussion'
 fieldMappings:
-  taxonomy_forums:
+  title:
     properties:
-      - 'sioc:has_container'
+      - 'schema:name'
+  created:
+    properties:
+      - 'schema:dateCreated'
+    datatype_callback: 'date_iso8601'
+  changed:
+    properties:
+      - 'schema:dateModified'
+    datatype_callback: 'date_iso8601'
+  body:
+    properties:
+      - 'schema:text'
+  uid:
+    properties:
+      - 'schema:author'
     mapping_type: 'rel'
+  comment_count:
+    properties:
+      - 'schema:interactionCount'
+    datatype_callback: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
diff --git a/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml b/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml
index f412f6a..aaaf536 100644
--- a/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml
+++ b/core/modules/forum/config/rdf.mapping.taxonomy_term.forums.yml
@@ -4,3 +4,10 @@ bundle: forums
 types:
   - 'sioc:Container'
   - 'sioc:Forum'
+fieldMappings:
+  name:
+    properties:
+      - 'schema:name'
+  description:
+    properties:
+      - 'schema:description'
diff --git a/core/modules/forum/forum.install b/core/modules/forum/forum.install
index e0219ff..9f16099 100644
--- a/core/modules/forum/forum.install
+++ b/core/modules/forum/forum.install
@@ -11,10 +11,11 @@
 function forum_install() {
   // Set the weight of the forum.module to 1 so it is loaded after the taxonomy.module.
   module_set_weight('forum', 1);
-  // Do not allow to delete the forum's node type machine name.
-  $locked = Drupal::state()->get('node.type.locked');
-  $locked['forum'] = 'forum';
-  Drupal::state()->set('node.type.locked', $locked);
+  // Forum topics are published by default, but do not have any other default
+  // options set (for example, they are not promoted to the front page).
+  // @todo Convert to default module configuration, once Node module's content
+  //   types are converted.
+  variable_set('node_options_forum', array('status'));
 }
 
 /**
@@ -105,6 +106,11 @@ function forum_enable() {
       ))
       ->save();
   }
+
+  // Ensure the forum node type is available.
+  node_types_rebuild();
+  $types = node_type_get_types();
+  node_add_body_field($types['forum']);
 }
 
 /**
@@ -114,6 +120,8 @@ function forum_uninstall() {
   // Load the dependent Taxonomy module, in case it has been disabled.
   drupal_load('module', 'taxonomy');
 
+  variable_del('node_options_forum');
+
   if ($field = field_info_field('taxonomy_forums')) {
     $field->delete();
   }
@@ -121,10 +129,6 @@ function forum_uninstall() {
   // Purge field data now to allow taxonomy module to be uninstalled
   // if this is the only field remaining.
   field_purge_batch(10);
-  // Allow to delete a forum's node type.
-  $locked = Drupal::state()->get('node.type.locked');
-  unset($locked['forum']);
-  Drupal::state()->set('node.type.locked', $locked);
 }
 
 /**
diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 11a1054..fedeb2d 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -174,13 +174,13 @@ function forum_menu_local_tasks(&$data, $router_item, $root_path) {
       $links = array();
       // Loop through all bundles for forum taxonomy vocabulary field.
       $field = field_info_field('taxonomy_forums');
-      foreach ($field['bundles']['node'] as $type_name) {
-        if (($type = entity_load('node_type', $type_name)) && node_access('create', $type_name)) {
-          $links[$type_name] = array(
+      foreach ($field['bundles']['node'] as $type) {
+        if (node_access('create', $type)) {
+          $links[$type] = array(
             '#theme' => 'menu_local_action',
             '#link' => array(
-              'title' => t('Add new @node_type', array('@node_type' => $type->label())),
-              'href' => 'node/add/' . $type_name . '/' . $forum_term->id(),
+              'title' => t('Add new @node_type', array('@node_type' => node_type_get_label($type))),
+              'href' => 'node/add/' . $type . '/' . $forum_term->id(),
             ),
           );
         }
@@ -427,6 +427,20 @@ function forum_node_load($nodes) {
 }
 
 /**
+ * Implements hook_node_info().
+ */
+function forum_node_info() {
+  return array(
+    'forum' => array(
+      'name' => t('Forum topic'),
+      'base' => 'forum',
+      'description' => t('A <em>forum topic</em> starts a new discussion thread within a forum.'),
+      'title_label' => t('Subject'),
+    )
+  );
+}
+
+/**
  * Implements hook_permission().
  */
 function forum_permission() {
diff --git a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
index 9cd6ae9..c28b1dc 100644
--- a/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
+++ b/core/modules/forum/lib/Drupal/forum/Tests/ForumTest.php
@@ -204,7 +204,7 @@ function testForum() {
 
     // Test loading multiple forum nodes on the front page.
     $this->drupalLogin($this->drupalCreateUser(array('administer content types', 'create forum content', 'post comments')));
-    $this->drupalPost('admin/structure/types/manage/forum', array('settings[node][options][promote]' => 'promote'), t('Save content type'));
+    $this->drupalPost('admin/structure/types/manage/forum', array('node_options[promote]' => 'promote'), t('Save content type'));
     $this->createForumTopic($this->forum, FALSE);
     $this->createForumTopic($this->forum, FALSE);
     $this->drupalGet('node');
diff --git a/core/modules/image/image.field.inc b/core/modules/image/image.field.inc
index 9609960..7b2f4c6 100644
--- a/core/modules/image/image.field.inc
+++ b/core/modules/image/image.field.inc
@@ -22,7 +22,7 @@ function image_field_info() {
         'column_groups' => array(
           'file' => array(
             'label' => t('File'),
-            'columns' => array('target_id', 'width', 'height'),
+            'columns' => array('fid', 'width', 'height'),
           ),
           'alt' => array(
             'label' => t('Alt'),
@@ -230,7 +230,7 @@ function image_field_presave(EntityInterface $entity, $field, $instance, $langco
   // Determine the dimensions if necessary.
   foreach ($items as &$item) {
     if (!isset($item['width']) || !isset($item['height'])) {
-      $info = image_get_info(file_load($item['target_id'])->getFileUri());
+      $info = image_get_info(file_load($item['fid'])->getFileUri());
 
       if (is_array($info)) {
         $item['width'] = $info['width'];
diff --git a/core/modules/image/image.install b/core/modules/image/image.install
index fd440da..8a05660 100644
--- a/core/modules/image/image.install
+++ b/core/modules/image/image.install
@@ -6,7 +6,6 @@
  */
 
 use Drupal\Component\Uuid\Uuid;
-use Drupal\field\Plugin\Core\Entity\Field;
 
 /**
  * Implements hook_install().
@@ -31,10 +30,10 @@ function image_uninstall() {
 function image_field_schema($field) {
   return array(
     'columns' => array(
-      'target_id' => array(
-        'description' => 'The ID of the target entity.',
+      'fid' => array(
+        'description' => 'The {file_managed}.fid being referenced in this field.',
         'type' => 'int',
-        'not null' => TRUE,
+        'not null' => FALSE,
         'unsigned' => TRUE,
       ),
       'alt' => array(
@@ -61,12 +60,12 @@ function image_field_schema($field) {
       ),
     ),
     'indexes' => array(
-      'target_id' => array('target_id'),
+      'fid' => array('fid'),
     ),
     'foreign keys' => array(
-      'target_id' => array(
+      'fid' => array(
         'table' => 'file_managed',
-        'columns' => array('target_id' => 'fid'),
+        'columns' => array('fid' => 'fid'),
       ),
     ),
   );
diff --git a/core/modules/image/image.views.inc b/core/modules/image/image.views.inc
index 2e70c08..77c4ea3 100644
--- a/core/modules/image/image.views.inc
+++ b/core/modules/image/image.views.inc
@@ -18,11 +18,11 @@
 function image_field_views_data($field) {
   $data = field_views_field_default_views_data($field);
   foreach ($data as $table_name => $table_data) {
-    // Add the relationship only on the target_id field.
-    $data[$table_name][$field['field_name'] . '_target_id']['relationship'] = array(
+    // Add the relationship only on the fid field.
+    $data[$table_name][$field['field_name'] . '_fid']['relationship'] = array(
       'id' => 'standard',
       'base' => 'file_managed',
-      'base field' => 'target_id',
+      'base field' => 'fid',
       'label' => t('image from !field_name', array('!field_name' => $field['field_name'])),
     );
   }
@@ -52,7 +52,7 @@ function image_field_views_data_views_data_alter(&$data, $field) {
       'id' => 'entity_reverse',
       'field_name' => $field['field_name'],
       'field table' => _field_sql_storage_tablename($field),
-      'field field' => $field['field_name'] . '_target_id',
+      'field field' => $field['field_name'] . '_fid',
       'base' => $entity_info['base_table'],
       'base field' => $entity_info['entity_keys']['id'],
       'label' => t('!field_name', array('!field_name' => $field['field_name'])),
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
index 973a8ef..96941b3 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageAdminStylesTest.php
@@ -273,7 +273,7 @@ function testStyleReplacement() {
 
     // Test that image is displayed using newly created style.
     $this->drupalGet('node/' . $nid);
-    $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name)));
+    $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name)));
 
     // Rename the style and make sure the image field is updated.
     $new_style_name = strtolower($this->randomName(10));
@@ -285,7 +285,7 @@ function testStyleReplacement() {
     $this->drupalPost($style_path . $style_name, $edit, t('Update style'));
     $this->assertText(t('Changes to the style have been saved.'), format_string('Style %name was renamed to %new_name.', array('%name' => $style_name, '%new_name' => $new_style_name)));
     $this->drupalGet('node/' . $nid);
-    $this->assertRaw(image_style_url($new_style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.');
+    $this->assertRaw(image_style_url($new_style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri()), 'Image displayed using style replacement style.');
 
     // Delete the style and choose a replacement style.
     $edit = array(
@@ -296,7 +296,7 @@ function testStyleReplacement() {
     $this->assertRaw($message);
 
     $this->drupalGet('node/' . $nid);
-    $this->assertRaw(image_style_url('thumbnail', file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), 'Image displayed using style replacement style.');
+    $this->assertRaw(image_style_url('thumbnail', file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri()), 'Image displayed using style replacement style.');
   }
 
   /**
@@ -362,7 +362,7 @@ function testConfigImport() {
 
     // Test that image is displayed using newly created style.
     $this->drupalGet('node/' . $nid);
-    $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name)));
+    $this->assertRaw(image_style_url($style_name, file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri()), format_string('Image displayed using style @style.', array('@style' => $style_name)));
 
     // Copy config to staging, and delete the image style.
     $staging = $this->container->get('config.storage.staging');
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
index c0f0cfd..ccc39bd 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageFieldDisplayTest.php
@@ -58,7 +58,7 @@ function _testImageFieldFormatters($scheme) {
     $node = node_load($nid, TRUE);
 
     // Test that the default formatter is being used.
-    $image_uri = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri();
+    $image_uri = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri();
     $image_info = array(
       'uri' => $image_uri,
       'width' => 40,
@@ -165,7 +165,7 @@ function testImageFieldSettings() {
     // style.
     $node = node_load($nid, TRUE);
     $image_info = array(
-      'uri' => file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri(),
+      'uri' => file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri(),
       'width' => 220,
       'height' => 110,
       'style_name' => 'medium',
@@ -175,7 +175,7 @@ function testImageFieldSettings() {
 
     // Add alt/title fields to the image and verify that they are displayed.
     $image_info = array(
-      'uri' => file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri(),
+      'uri' => file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri(),
       'alt' => $this->randomName(),
       'title' => $this->randomName(),
       'width' => 40,
@@ -243,7 +243,7 @@ function testImageFieldDefaultImage() {
     $nid = $this->uploadNodeImage($images[1], $field_name, 'article');
     $node = node_load($nid, TRUE);
     $image_info = array(
-      'uri' => file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri(),
+      'uri' => file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri(),
       'width' => 40,
       'height' => 20,
     );
diff --git a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php
index 5e7472f..0735bef 100644
--- a/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php
+++ b/core/modules/image/lib/Drupal/image/Tests/ImageItemTest.php
@@ -66,7 +66,7 @@ public function setUp() {
   public function testImageItem() {
     // Create a test entity with the image field set.
     $entity = entity_create('entity_test', array());
-    $entity->image_test->target_id = $this->image->id();
+    $entity->image_test->fid = $this->image->id();
     $entity->image_test->alt = $alt = $this->randomName();
     $entity->image_test->title = $title = $this->randomName();
     $entity->name->value = $this->randomName();
@@ -75,7 +75,7 @@ public function testImageItem() {
     $entity = entity_load('entity_test', $entity->id());
     $this->assertTrue($entity->image_test instanceof FieldInterface, 'Field implements interface.');
     $this->assertTrue($entity->image_test[0] instanceof FieldItemInterface, 'Field item implements interface.');
-    $this->assertEqual($entity->image_test->target_id, $this->image->id());
+    $this->assertEqual($entity->image_test->fid, $this->image->id());
     $this->assertEqual($entity->image_test->alt, $alt);
     $this->assertEqual($entity->image_test->title, $title);
     $info = image_get_info('public://example.jpg');
@@ -91,7 +91,7 @@ public function testImageItem() {
     ));
     $image2->save();
 
-    $entity->image_test->target_id = $image2->id();
+    $entity->image_test->fid = $image2->id();
     $entity->image_test->alt = $new_alt = $this->randomName();
     // The width and height is only updated when width is not set.
     $entity->image_test->width = NULL;
@@ -105,7 +105,7 @@ public function testImageItem() {
 
     // Check that the image item can be set to the referenced file directly.
     $entity->image_test = $this->image;
-    $this->assertEqual($entity->image_test->target_id, $this->image->id());
+    $this->assertEqual($entity->image_test->fid, $this->image->id());
 
     // Delete the image and try to save the entity again.
     $this->image->delete();
diff --git a/core/modules/image/lib/Drupal/image/Type/ImageItem.php b/core/modules/image/lib/Drupal/image/Type/ImageItem.php
index 7d441fd..2dcf2b4 100644
--- a/core/modules/image/lib/Drupal/image/Type/ImageItem.php
+++ b/core/modules/image/lib/Drupal/image/Type/ImageItem.php
@@ -7,12 +7,12 @@
 
 namespace Drupal\image\Type;
 
-use Drupal\field\Plugin\Type\FieldType\ConfigEntityReferenceItemBase;
+use Drupal\field\Plugin\field\field_type\LegacyConfigFieldItem;
 
 /**
  * Defines the 'image_field' entity field item.
  */
-class ImageItem extends ConfigEntityReferenceItemBase {
+class ImageItem extends LegacyConfigFieldItem {
 
   /**
    * Property definitions of the contained properties.
@@ -24,14 +24,14 @@ class ImageItem extends ConfigEntityReferenceItemBase {
   static $propertyDefinitions;
 
   /**
-   * {@inheritdoc}
+   * Implements \Drupal\Core\TypedData\ComplexDataInterface::getPropertyDefinitions().
    */
   public function getPropertyDefinitions() {
-    $this->definition['settings']['target_type'] = 'file';
-
     if (!isset(static::$propertyDefinitions)) {
-      static::$propertyDefinitions = parent::getPropertyDefinitions();
-
+      static::$propertyDefinitions['fid'] = array(
+        'type' => 'integer',
+        'label' => t('Referenced file id.'),
+      );
       static::$propertyDefinitions['alt'] = array(
         'type' => 'string',
         'label' => t("Alternative image text, for the image's 'alt' attribute."),
@@ -48,8 +48,39 @@ public function getPropertyDefinitions() {
         'type' => 'integer',
         'label' => t('The height of the image in pixels.'),
       );
+      static::$propertyDefinitions['entity'] = array(
+        'type' => 'entity',
+        'constraints' => array(
+          'EntityType' => 'file',
+        ),
+        'label' => t('Image'),
+        'description' => t('The referenced file'),
+        // The entity object is computed out of the fid.
+        'computed' => TRUE,
+        'read-only' => FALSE,
+        'settings' => array('id source' => 'fid'),
+      );
     }
     return static::$propertyDefinitions;
   }
 
+  /**
+   * Overrides \Drupal\Core\Entity\Field\FieldItemBase::get().
+   */
+  public function setValue($values, $notify = TRUE) {
+    // Treat the values as value of the entity property, if no array is
+    // given as this handles entity IDs and objects.
+    if (isset($values) && !is_array($values)) {
+      // Directly update the property instead of invoking the parent, so that
+      // the entity property can take care of updating the ID property.
+      $this->properties['entity']->setValue($values, $notify);
+    }
+    else {
+      // Make sure that the 'entity' property gets set as 'target_id'.
+      if (isset($values['fid']) && !isset($values['entity'])) {
+        $values['entity'] = $values['fid'];
+      }
+      parent::setValue($values, $notify);
+    }
+  }
 }
diff --git a/core/modules/language/language.module b/core/modules/language/language.module
index f18d494..6b45fa1 100644
--- a/core/modules/language/language.module
+++ b/core/modules/language/language.module
@@ -5,7 +5,6 @@
  * Add language handling functionality to Drupal.
  */
 
-use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Language\Language;
 
 /**
@@ -323,18 +322,6 @@ function language_configuration_element_process($element, &$form_state, &$form)
     ),
   );
 
-  // Do not add the submit callback for the language content settings page,
-  // which is handled separately.
-  if (array_search('language_content_settings_form_submit', $form['#submit']) === FALSE) {
-    // Determine where to attach the language_configuration element submit handler.
-    // @todo Form API: Allow form widgets/sections to declare #submit handlers.
-    if (isset($form['actions']['submit']['#submit']) && array_search('language_configuration_element_submit', $form['actions']['submit']['#submit']) === FALSE) {
-      $form['actions']['submit']['#submit'][] = 'language_configuration_element_submit';
-    }
-    elseif (array_search('language_configuration_element_submit', $form['#submit']) === FALSE) {
-      $form['#submit'][] = 'language_configuration_element_submit';
-    }
-  }
   return $element;
 }
 
@@ -425,10 +412,10 @@ function language_get_default_configuration_settings_key($entity_type, $bundle)
 /**
  * Implements hook_node_type_update().
  */
-function language_node_type_update(NodeTypeInterface $type) {
-  if ($type->original->id() != $type->id()) {
-    language_save_default_configuration('node', $type->id(), language_get_default_configuration('node', $type->original->id()));
-    language_clear_default_configuration('node', $type->original->id());
+function language_node_type_update($info) {
+  if (!empty($info->old_type) && $info->old_type != $info->type) {
+    language_save_default_configuration('node', $info->type, language_get_default_configuration('node', $info->old_type));
+    language_clear_default_configuration('node', $info->old_type);
   }
 }
 
diff --git a/core/modules/locale/locale.module b/core/modules/locale/locale.module
index 460e5e5..dcca8bf 100644
--- a/core/modules/locale/locale.module
+++ b/core/modules/locale/locale.module
@@ -166,8 +166,7 @@ function locale_help($path, $arg) {
 
     case 'admin/config/regional/translate/import':
       $output = '<p>' . t('Translation files are automatically downloaded and imported when <a href="@language">languages</a> are added, or when modules or themes are enabled.', array('@language' => url('admin/config/regional/language'))). '</p>';
-      $output .= '<p>' . t('This page allows translators to manually import translated strings contained in a Gettext Portable Object (.po) file. Manual import may be used for customized translations or for the translation of custom modules and themes. To customize translations you can download a translation file from the <a href="@url">Drupal translation server</a> or <a href="@export">export</a> translations from the site, customize the translations using a Gettext translation editor, and import the result using this page.', array('@url' => 'http://localize.drupal.org', '@export' => url('admin/config/regional/translate/export'))) . '</p>';
-      $output .= '<p>' . t('Note that importing large .po files may take several minutes.') . '</p>';
+      $output .= '<p>' . t('For situations where translations need to be manually imported, this page imports the translated strings contained in a Gettext Portable Object (.po) file, which can be downloaded from the <a href="@url">Drupal translation server</a>. Alternatively, a .po file may need to be imported after offline editing in a Gettext translation editor. Importing an individual .po file may be a lengthy process.', array('@url' => 'http://localize.drupal.org')) . '</p>';
       return $output;
 
     case 'admin/config/regional/translate/export':
diff --git a/core/modules/menu/lib/Drupal/menu/MenuAccessController.php b/core/modules/menu/lib/Drupal/menu/MenuAccessController.php
deleted file mode 100644
index 4cb2962..0000000
--- a/core/modules/menu/lib/Drupal/menu/MenuAccessController.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\menu\MenuAccessController.
- */
-
-namespace Drupal\menu;
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines the access controller for the menu entity type.
- */
-class MenuAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
-    if ($operation === 'view') {
-      return TRUE;
-    }
-    elseif ($operation == 'delete') {
-      // System menus could not be deleted.
-      $system_menus = menu_list_system_menus();
-      if (isset($system_menus[$entity->id()])) {
-        return FALSE;
-      }
-    }
-
-    if (in_array($operation, array('create', 'update', 'delete'))) {
-      return user_access('administer menu', $account);
-    }
-  }
-
-}
diff --git a/core/modules/menu/lib/Drupal/menu/MenuListController.php b/core/modules/menu/lib/Drupal/menu/MenuListController.php
index 139c40b..dfa6019 100644
--- a/core/modules/menu/lib/Drupal/menu/MenuListController.php
+++ b/core/modules/menu/lib/Drupal/menu/MenuListController.php
@@ -41,24 +41,27 @@ public function buildRow(EntityInterface $entity) {
   }
 
   /**
-   * {@inheritdoc}
+   * Overrides \Drupal\Core\Entity\EntityListController::getOperations();
    */
   public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
     $uri = $entity->uri();
 
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Edit menu');
-    }
-    if (isset($operations['delete'])) {
-      $operations['delete']['title'] = t('Delete menu');
-    }
+    $operations['edit']['title'] = t('Edit menu');
     $operations['add'] = array(
       'title' => t('Add link'),
       'href' => $uri['path'] . '/add',
       'options' => $uri['options'],
       'weight' => 20,
     );
+    // System menus could not be deleted.
+    $system_menus = menu_list_system_menus();
+    if (isset($system_menus[$entity->id()])) {
+      unset($operations['delete']);
+    }
+    else {
+      $operations['delete']['title'] = t('Delete menu');
+    }
     return $operations;
   }
 
diff --git a/core/modules/menu/menu.module b/core/modules/menu/menu.module
index 18b0ee5..68c3125 100644
--- a/core/modules/menu/menu.module
+++ b/core/modules/menu/menu.module
@@ -146,7 +146,6 @@ function menu_menu() {
  */
 function menu_entity_info(&$entity_info) {
   $entity_info['menu']['controllers']['list'] = 'Drupal\menu\MenuListController';
-  $entity_info['menu']['controllers']['access'] = 'Drupal\menu\MenuAccessController';
   $entity_info['menu']['uri_callback'] = 'menu_uri';
   $entity_info['menu']['controllers']['form'] = array(
     'default' => 'Drupal\menu\MenuFormController',
@@ -671,7 +670,7 @@ function menu_node_submit(EntityInterface $node, $form, $form_state) {
  */
 function menu_form_node_type_form_alter(&$form, $form_state) {
   $menu_options = menu_get_menus();
-  $type = $form_state['controller']->getEntity();
+  $type = $form['#node_type'];
   $form['menu'] = array(
     '#type' => 'details',
     '#title' => t('Menu settings'),
@@ -684,7 +683,7 @@ function menu_form_node_type_form_alter(&$form, $form_state) {
   $form['menu']['menu_options'] = array(
     '#type' => 'checkboxes',
     '#title' => t('Available menus'),
-    '#default_value' => variable_get('menu_options_' . $type->id(), array('main')),
+    '#default_value' => variable_get('menu_options_' . $type->type, array('main')),
     '#options' => $menu_options,
     '#description' => t('The menus available to place links in for this content type.'),
   );
@@ -697,7 +696,7 @@ function menu_form_node_type_form_alter(&$form, $form_state) {
   $form['menu']['menu_parent'] = array(
     '#type' => 'select',
     '#title' => t('Default parent item'),
-    '#default_value' => variable_get('menu_parent_' . $type->id(), 'main:0'),
+    '#default_value' => variable_get('menu_parent_' . $type->type, 'main:0'),
     '#options' => $options,
     '#description' => t('Choose the menu item to be the default parent for a new link in the content authoring form.'),
     '#attributes' => array('class' => array('menu-title-select')),
diff --git a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php
index b6d3f75..fa0d4c5 100644
--- a/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php
+++ b/core/modules/menu_link/lib/Drupal/menu_link/MenuLinkFormController.php
@@ -52,10 +52,13 @@ class MenuLinkFormController extends EntityFormController implements EntityContr
   /**
    * Constructs a new MenuLinkFormController object.
    *
+   * @param string $operation
+   *   The name of the current operation.
    * @param \Drupal\Core\Path\AliasManagerInterface $path_alias_manager
    *   The path alias manager.
    */
-  public function __construct(MenuLinkStorageControllerInterface $menu_link_storage_controller, AliasManagerInterface $path_alias_manager, UrlGenerator $url_generator, ModuleHandlerInterface $module_handler) {
+  public function __construct($operation, MenuLinkStorageControllerInterface $menu_link_storage_controller, AliasManagerInterface $path_alias_manager, UrlGenerator $url_generator, ModuleHandlerInterface $module_handler) {
+    parent::__construct($operation);
     $this->menuLinkStorageController = $menu_link_storage_controller;
     $this->pathAliasManager = $path_alias_manager;
     $this->urlGenerator = $url_generator;
@@ -65,8 +68,9 @@ public function __construct(MenuLinkStorageControllerInterface $menu_link_storag
   /**
    * {@inheritdoc}
    */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info, $operation = NULL) {
     return new static(
+      $operation,
       $container->get('plugin.manager.entity')->getStorageController('menu_link'),
       $container->get('path.alias_manager.cached'),
       $container->get('url_generator'),
diff --git a/core/modules/node/content_types.inc b/core/modules/node/content_types.inc
new file mode 100644
index 0000000..156576b
--- /dev/null
+++ b/core/modules/node/content_types.inc
@@ -0,0 +1,491 @@
+<?php
+
+/**
+ * @file
+ * Content type editing user interface.
+ */
+
+/**
+ * Page callback: Displays the content type admin overview page.
+ *
+ * @return array
+ *   An array as expected by drupal_render().
+ *
+ * @see node_menu()
+ */
+function node_overview_types() {
+  $types = node_type_get_types();
+  $names = node_type_get_names();
+  $field_ui = module_exists('field_ui');
+  $header = array(t('Name'), t('Operations'));
+  $rows = array();
+
+  foreach ($names as $key => $name) {
+    $type = $types[$key];
+    $row = array(theme('node_admin_overview', array('name' => $name, 'type' => $type)));
+    if ($field_ui && user_access('administer node fields')) {
+      $links['fields'] = array(
+        'title' => t('Manage fields'),
+        'href' => 'admin/structure/types/manage/' . $type->type . '/fields',
+        'weight' => 0,
+      );
+    }
+    if ($field_ui && user_access('administer node display')) {
+      $links['display'] = array(
+        'title' => t('Manage display'),
+        'href' => 'admin/structure/types/manage/' . $type->type . '/display',
+        'weight' => 5,
+      );
+    }
+
+    $links['edit'] = array(
+      'title' => t('Edit'),
+      'href' => 'admin/structure/types/manage/' . $type->type,
+      'weight' => 10,
+    );
+
+    if ($type->custom) {
+      $links['delete'] = array(
+        'title' => t('Delete'),
+        'href' => 'admin/structure/types/manage/' . $type->type . '/delete',
+        'weight' => 15,
+      );
+    }
+
+    $row[] = array(
+      'data' => array(
+        '#type' => 'operations',
+        '#links' => $links,
+      ),
+    );
+
+    $rows[] = $row;
+  }
+
+  $build['node_table'] = array(
+    '#theme' => 'table',
+    '#header' => $header,
+    '#rows' => $rows,
+    '#empty' => t('No content types available. <a href="@link">Add content type</a>.', array('@link' => url('admin/structure/types/add'))),
+  );
+
+  return $build;
+}
+
+/**
+ * Returns HTML for a node type description for the content type admin page.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - name: The human-readable name of the content type.
+ *   - type: An object containing the 'type' (machine name) and 'description' of
+ *     the content type.
+ *
+ * @return string
+ *   An HTML-formatted string of the description for this node type.
+ *
+ * @ingroup themeable
+ */
+function theme_node_admin_overview($variables) {
+  $name = $variables['name'];
+  $type = $variables['type'];
+
+  $output = check_plain($name);
+  $output .= ' <small>' . t('(Machine name: @type)', array('@type' => $type->type)) . '</small>';
+  $output .= '<div class="description">' . filter_xss_admin($type->description) . '</div>';
+  return $output;
+}
+
+/**
+ * Form constructor for the node type editing form.
+ *
+ * @param $type
+ *   (optional) An object representing the node type, when editing an existing
+ *   node type.
+ *
+ * @see node_type_form_validate()
+ * @see node_type_form_submit()
+ * @ingroup forms
+ */
+function node_type_form($form, &$form_state, $type = NULL) {
+  if (!isset($type->type)) {
+    // This is a new type. Node module managed types are custom and unlocked.
+    $type = node_type_set_defaults(array('custom' => 1, 'locked' => 0));
+  }
+
+  // Make the type object available to implementations of hook_form_alter.
+  $form['#node_type'] = $type;
+
+  $form['name'] = array(
+    '#title' => t('Name'),
+    '#type' => 'textfield',
+    '#default_value' => $type->name,
+    '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
+    '#required' => TRUE,
+    '#size' => 30,
+  );
+
+  $form['type'] = array(
+    '#type' => 'machine_name',
+    '#default_value' => $type->type,
+    '#maxlength' => 32,
+    '#disabled' => $type->locked,
+    '#machine_name' => array(
+      'exists' => 'node_type_load',
+      'source' => array('name'),
+    ),
+    '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array(
+      '%node-add' => t('Add new content'),
+    )),
+  );
+
+  $form['description'] = array(
+    '#title' => t('Description'),
+    '#type' => 'textarea',
+    '#default_value' => $type->description,
+    '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content</em> page.'),
+  );
+
+  $form['additional_settings'] = array(
+    '#type' => 'vertical_tabs',
+    '#attached' => array(
+      'library' => array(array('node', 'drupal.content_types')),
+    ),
+  );
+
+  $form['submission'] = array(
+    '#type' => 'details',
+    '#title' => t('Submission form settings'),
+    '#group' => 'additional_settings',
+  );
+  $form['submission']['title_label'] = array(
+    '#title' => t('Title field label'),
+    '#type' => 'textfield',
+    '#default_value' => $type->title_label,
+    '#required' => TRUE,
+  );
+  if (!$type->has_title) {
+    // Avoid overwriting a content type that intentionally does not have a
+    // title field.
+    $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
+    $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
+    $form['submission']['title_label']['#required'] = FALSE;
+  }
+  $form['submission']['node_preview'] = array(
+    '#type' => 'radios',
+    '#title' => t('Preview before submitting'),
+    '#default_value' => variable_get('node_preview_' . $type->type, DRUPAL_OPTIONAL),
+    '#options' => array(
+      DRUPAL_DISABLED => t('Disabled'),
+      DRUPAL_OPTIONAL => t('Optional'),
+      DRUPAL_REQUIRED => t('Required'),
+    ),
+  );
+  $form['submission']['help']  = array(
+    '#type' => 'textarea',
+    '#title' => t('Explanation or submission guidelines'),
+    '#default_value' => $type->help,
+    '#description' => t('This text will be displayed at the top of the page when creating or editing content of this type.'),
+  );
+  $form['workflow'] = array(
+    '#type' => 'details',
+    '#title' => t('Publishing options'),
+    '#collapsed' => TRUE,
+    '#group' => 'additional_settings',
+  );
+  $form['workflow']['node_options'] = array('#type' => 'checkboxes',
+    '#title' => t('Default options'),
+    '#default_value' => variable_get('node_options_' . $type->type, array('status', 'promote')),
+    '#options' => array(
+      'status' => t('Published'),
+      'promote' => t('Promoted to front page'),
+      'sticky' => t('Sticky at top of lists'),
+      'revision' => t('Create new revision'),
+    ),
+    '#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
+  );
+  if (module_exists('language')) {
+    $form['language'] = array(
+      '#type' => 'details',
+      '#title' => t('Language settings'),
+      '#collapsed' => TRUE,
+      '#group' => 'additional_settings',
+    );
+
+    $language_configuration = language_get_default_configuration('node', $type->type);
+    $form['language']['language_configuration'] = array(
+      '#type' => 'language_configuration',
+      '#entity_information' => array(
+        'entity_type' => 'node',
+        'bundle' => $type->type,
+      ),
+      '#default_value' => $language_configuration,
+    );
+
+    $form['#submit'][] = 'language_configuration_element_submit';
+  }
+  $form['display'] = array(
+    '#type' => 'details',
+    '#title' => t('Display settings'),
+    '#collapsed' => TRUE,
+    '#group' => 'additional_settings',
+  );
+  $form['display']['node_submitted'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Display author and date information.'),
+    '#default_value' => variable_get('node_submitted_' . $type->type, TRUE),
+    '#description' => t('Author username and publish date will be displayed.'),
+  );
+  $form['old_type'] = array(
+    '#type' => 'value',
+    '#value' => $type->type,
+  );
+  $form['orig_type'] = array(
+    '#type' => 'value',
+    '#value' => isset($type->orig_type) ? $type->orig_type : '',
+  );
+  $form['base'] = array(
+    '#type' => 'value',
+    '#value' => $type->base,
+  );
+  $form['custom'] = array(
+    '#type' => 'value',
+    '#value' => $type->custom,
+  );
+  $form['modified'] = array(
+    '#type' => 'value',
+    '#value' => $type->modified,
+  );
+  $form['locked'] = array(
+    '#type' => 'value',
+    '#value' => $type->locked,
+  );
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Save content type'),
+    '#weight' => 40,
+  );
+
+  if ($type->custom) {
+    if (!empty($type->type)) {
+      $form['actions']['delete'] = array(
+        '#type' => 'submit',
+        '#value' => t('Delete content type'),
+        '#weight' => 45,
+      );
+    }
+  }
+  $form['#submit'][] = 'node_type_form_submit';
+
+  return $form;
+}
+
+/**
+ * Helper function for teaser length choices.
+ *
+ * @param int $length
+ *   An integer representing the desired length of the teaser string.
+ *
+ * @return string
+ *   A string that reprents the teaser length options.
+ */
+function _node_characters($length) {
+  return ($length == 0) ? t('Unlimited') : format_plural($length, '1 character', '@count characters');
+}
+
+/**
+ * Form validation handler for node_type_form().
+ *
+ * @see node_type_form_submit()
+ */
+function node_type_form_validate($form, &$form_state) {
+  $type = new stdClass();
+  $type->type = $form_state['values']['type'];
+  $type->name = trim($form_state['values']['name']);
+
+  // Work out what the type was before the user submitted this form
+  $old_type = $form_state['values']['old_type'];
+
+  $types = node_type_get_names();
+
+  if (!$form_state['values']['locked']) {
+    // 'theme' conflicts with theme_node_form().
+    // '0' is invalid, since elsewhere we check it using empty().
+    if (in_array($type->type, array('0', 'theme'))) {
+      form_set_error('type', t("Invalid machine-readable name. Enter a name other than %invalid.", array('%invalid' => $type->type)));
+    }
+  }
+
+  $names = array_flip($types);
+
+  if (isset($names[$type->name]) && $names[$type->name] != $old_type) {
+    form_set_error('name', t('The human-readable name %name is already taken.', array('%name' => $type->name)));
+  }
+}
+
+/**
+ * Form submission handler for node_type_form().
+ *
+ * @see node_type_form_validate()
+ */
+function node_type_form_submit($form, &$form_state) {
+  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
+
+  $type = node_type_set_defaults();
+
+  $type->type = $form_state['values']['type'];
+  $type->name = trim($form_state['values']['name']);
+  $type->orig_type = trim($form_state['values']['orig_type']);
+  $type->old_type = isset($form_state['values']['old_type']) ? $form_state['values']['old_type'] : $type->type;
+
+  $type->description = $form_state['values']['description'];
+  $type->help = $form_state['values']['help'];
+  $type->title_label = $form_state['values']['title_label'];
+  // title_label is required in core; has_title will always be true, unless a
+  // module alters the title field.
+  $type->has_title = ($type->title_label != '');
+
+  $type->base = !empty($form_state['values']['base']) ? $form_state['values']['base'] : 'node_content';
+  $type->custom = $form_state['values']['custom'];
+  $type->modified = TRUE;
+  $type->locked = $form_state['values']['locked'];
+  if (isset($form['#node_type']->module)) {
+    $type->module = $form['#node_type']->module;
+  }
+
+  if ($op == t('Delete content type')) {
+    $form_state['redirect'] = 'admin/structure/types/manage/' . $type->old_type . '/delete';
+    return;
+  }
+
+  $variables = $form_state['values'];
+
+  // Remove everything that's been saved already - whatever's left is assumed
+  // to be a persistent variable.
+  foreach ($variables as $key => $value) {
+    if (isset($type->$key)) {
+      unset($variables[$key]);
+    }
+  }
+
+  unset($variables['form_token'], $variables['op'], $variables['submit'], $variables['delete'], $variables['reset'], $variables['form_id'], $variables['form_build_id']);
+
+  // Save or reset persistent variable values.
+  foreach ($variables as $key => $value) {
+    $variable_new = $key . '_' . $type->type;
+    $variable_old = $key . '_' . $type->old_type;
+
+    if (is_array($value)) {
+      $value = array_keys(array_filter($value));
+    }
+    variable_set($variable_new, $value);
+
+    if ($variable_new != $variable_old) {
+      variable_del($variable_old);
+    }
+  }
+
+  // Saving the content type after saving the variables allows modules to act
+  // on those variables via hook_node_type_insert().
+  $status = node_type_save($type);
+
+  node_types_rebuild();
+  menu_router_rebuild();
+  $t_args = array('%name' => $type->name);
+
+  if ($status == SAVED_UPDATED) {
+    drupal_set_message(t('The content type %name has been updated.', $t_args));
+  }
+  elseif ($status == SAVED_NEW) {
+    node_add_body_field($type);
+    drupal_set_message(t('The content type %name has been added.', $t_args));
+    watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/structure/types'));
+  }
+
+  $form_state['redirect'] = 'admin/structure/types';
+  return;
+}
+
+/**
+ * Implements hook_node_type_update().
+ */
+function node_node_type_update($info) {
+  if (!empty($info->old_type) && $info->old_type != $info->type) {
+    $update_count = node_type_update_nodes($info->old_type, $info->type);
+
+    if ($update_count) {
+      drupal_set_message(format_plural($update_count, 'Changed the content type of 1 post from %old-type to %type.', 'Changed the content type of @count posts from %old-type to %type.', array('%old-type' => $info->old_type, '%type' => $info->type)));
+    }
+  }
+}
+
+/**
+ * Resets relevant fields of a module-defined node type to their default values.
+ *
+ * @param $type
+ *   The node type to reset. The node type is passed back by reference with its
+ *   resetted values. If there is no module-defined info for this node type,
+ *   then nothing happens.
+ */
+function node_type_reset($type) {
+  $info_array = module_invoke_all('node_info');
+  if (isset($info_array[$type->orig_type])) {
+    $info_array[$type->orig_type]['type'] = $type->orig_type;
+    $info = node_type_set_defaults($info_array[$type->orig_type]);
+
+    foreach ($info as $field => $value) {
+      $type->$field = $value;
+    }
+  }
+}
+
+/**
+ * Page callback: Form constructor for the content type delete form.
+ *
+ * @param $type
+ *   Content type object.
+ *
+ * @return
+ *   Form array for delete confirmation form.
+ *
+ * @see node_type_delete_confirm_submit()
+ * @ingroup forms
+ */
+function node_type_delete_confirm($form, &$form_state, $type) {
+  $form['type'] = array('#type' => 'value', '#value' => $type->type);
+  $form['name'] = array('#type' => 'value', '#value' => $type->name);
+
+  $message = t('Are you sure you want to delete the content type %type?', array('%type' => $type->name));
+
+  $num_nodes = db_query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $type->type))->fetchField();
+  if ($num_nodes) {
+    drupal_set_title($message, PASS_THROUGH);
+    $caption = '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', array('%type' => $type->name)) . '</p>';
+    $form['description'] = array('#markup' => $caption);
+    return $form;
+  }
+
+  $caption = '<p>' . t('This action cannot be undone.') . '</p>';
+
+  return confirm_form($form, $message, 'admin/structure/types', $caption, t('Delete'));
+}
+
+/**
+ * Form submission handler for node_type_delete_confirm().
+ */
+function node_type_delete_confirm_submit($form, &$form_state) {
+  node_type_delete($form_state['values']['type']);
+
+  variable_del('node_preview_' . $form_state['values']['type']);
+  $t_args = array('%name' => $form_state['values']['name']);
+  drupal_set_message(t('The content type %name has been deleted.', $t_args));
+  watchdog('node', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
+
+  node_types_rebuild();
+  menu_router_rebuild();
+
+  $form_state['redirect'] = 'admin/structure/types';
+  return;
+}
diff --git a/core/modules/node/content_types.js b/core/modules/node/content_types.js
index f6a545b..40d6422 100644
--- a/core/modules/node/content_types.js
+++ b/core/modules/node/content_types.js
@@ -18,10 +18,10 @@ Drupal.behaviors.contentTypes = {
     });
     $context.find('#edit-workflow').drupalSetSummary(function(context) {
       var vals = [];
-      $(context).find("input[name^='settings[node][options']:checked").parent().each(function() {
+      $(context).find("input[name^='node_options']:checked").parent().each(function() {
         vals.push(Drupal.checkPlain($(this).text()));
       });
-      if (!$(context).find('#edit-settings-node-options-status').is(':checked')) {
+      if (!$(context).find('#edit-node-options-status').is(':checked')) {
         vals.unshift(Drupal.t('Not published'));
       }
       return vals.join(', ');
@@ -43,7 +43,7 @@ Drupal.behaviors.contentTypes = {
       $context.find('input:checked').next('label').each(function() {
         vals.push(Drupal.checkPlain($(this).text()));
       });
-      if (!$context.find('#edit-settings-node-submitted').is(':checked')) {
+      if (!$context.find('#edit-node-submitted').is(':checked')) {
         vals.unshift(Drupal.t("Don't display post information"));
       }
       return vals.join(', ');
diff --git a/core/modules/node/lib/Drupal/node/Form/NodeTypeDeleteConfirm.php b/core/modules/node/lib/Drupal/node/Form/NodeTypeDeleteConfirm.php
deleted file mode 100644
index 23973c9..0000000
--- a/core/modules/node/lib/Drupal/node/Form/NodeTypeDeleteConfirm.php
+++ /dev/null
@@ -1,95 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Form\NodeTypeDeleteConfirm.
- */
-
-namespace Drupal\node\Form;
-
-use Drupal\Core\Entity\EntityConfirmFormBase;
-use Drupal\Core\Entity\EntityControllerInterface;
-use Drupal\Core\Database\Connection;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Provides a form for content type deletion.
- */
-class NodeTypeDeleteConfirm extends EntityConfirmFormBase implements EntityControllerInterface {
-
-  /**
-   * The database connection.
-   *
-   * @var \Drupal\Core\Database\Connection
-   */
-  protected $database;
-
-  /**
-   * Constructs a new NodeTypeDeleteConfirm object.
-   *
-   * @param \Drupal\Core\Database\Connection $database
-   *   The database connection.
-   */
-  public function __construct(Connection $database) {
-    $this->database = $database;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
-    return new static(
-      $container->get('database')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getQuestion() {
-    return t('Are you sure you want to delete the content type %type?', array('%type' => $this->entity->label()));
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getCancelPath() {
-    return 'admin/structure/types';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getConfirmText() {
-    return t('Delete');
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL) {
-    $num_nodes = $this->database->query("SELECT COUNT(*) FROM {node} WHERE type = :type", array(':type' => $this->entity->id()))->fetchField();
-    if ($num_nodes) {
-      drupal_set_title($this->getQuestion(), PASS_THROUGH);
-      $caption = '<p>' . format_plural($num_nodes, '%type is used by 1 piece of content on your site. You can not remove this content type until you have removed all of the %type content.', '%type is used by @count pieces of content on your site. You may not remove %type until you have removed all of the %type content.', array('%type' => $this->entity->label())) . '</p>';
-      $form['description'] = array('#markup' => $caption);
-      return $form;
-    }
-
-    return parent::buildForm($form, $form_state, $request);
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submit(array $form, array &$form_state) {
-    $this->entity->delete();
-    $t_args = array('%name' => $this->entity->label());
-    drupal_set_message(t('The content type %name has been deleted.', $t_args));
-    watchdog('node', 'Deleted content type %name.', $t_args, WATCHDOG_NOTICE);
-
-    $form_state['redirect'] = $this->getCancelPath();
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/NodeFormController.php b/core/modules/node/lib/Drupal/node/NodeFormController.php
index 2c362b6..e64db93 100644
--- a/core/modules/node/lib/Drupal/node/NodeFormController.php
+++ b/core/modules/node/lib/Drupal/node/NodeFormController.php
@@ -18,13 +18,6 @@
 class NodeFormController extends EntityFormController {
 
   /**
-   * Default settings for this content/node type.
-   *
-   * @var array
-   */
-  protected $settings;
-
-  /**
    * Prepares the node object.
    *
    * Fills in a few default values, and then invokes hook_node_prepare() on all
@@ -35,20 +28,13 @@ class NodeFormController extends EntityFormController {
   protected function prepareEntity() {
     $node = $this->entity;
     // Set up default values, if required.
-    $type = entity_load('node_type', $node->bundle());
-    $this->settings = $type->getModuleSettings('node');
-    $this->settings += array(
-      'options' => array('status', 'promote'),
-      'preview' => DRUPAL_OPTIONAL,
-      'submitted' => TRUE,
-    );
-
+    $node_options = variable_get('node_options_' . $node->type, array('status', 'promote'));
     // If this is a new node, fill in the default values.
     if (!isset($node->nid) || isset($node->is_new)) {
       foreach (array('status', 'promote', 'sticky') as $key) {
         // Multistep node forms might have filled in something already.
         if (!isset($node->$key)) {
-          $node->$key = (int) in_array($key, $this->settings['options']);
+          $node->$key = (int) in_array($key, $node_options);
         }
       }
       global $user;
@@ -61,7 +47,7 @@ protected function prepareEntity() {
       $node->log = NULL;
     }
     // Always use the default revision setting.
-    $node->setNewRevision(in_array('revision', $this->settings['options']));
+    $node->setNewRevision(in_array('revision', $node_options));
 
     module_invoke_all('node_prepare', $node);
   }
@@ -254,7 +240,7 @@ public function form(array $form, array &$form_state) {
   protected function actions(array $form, array &$form_state) {
     $element = parent::actions($form, $form_state);
     $node = $this->entity;
-    $preview_mode = $this->settings['preview'];
+    $preview_mode = variable_get('node_preview_' . $node->type, DRUPAL_OPTIONAL);
 
     $element['submit']['#access'] = $preview_mode != DRUPAL_REQUIRED || (!form_get_errors() && isset($form_state['node_preview']));
 
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeAccessController.php b/core/modules/node/lib/Drupal/node/NodeTypeAccessController.php
deleted file mode 100644
index 40327e3..0000000
--- a/core/modules/node/lib/Drupal/node/NodeTypeAccessController.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\taxonomy\NodeTypeAccessController.
- */
-
-namespace Drupal\node;
-
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines an access controller for the node type entity.
- *
- * @see \Drupal\node\Plugin\Core\Entity\NodeType.
- */
-class NodeTypeAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
-    if ($operation == 'delete' && $entity->isLocked()) {
-      return FALSE;
-    }
-    return user_access('administer content types', $account);
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeFormController.php b/core/modules/node/lib/Drupal/node/NodeTypeFormController.php
deleted file mode 100644
index aaa287b..0000000
--- a/core/modules/node/lib/Drupal/node/NodeTypeFormController.php
+++ /dev/null
@@ -1,280 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\NodeTypeFormController.
- */
-
-namespace Drupal\node;
-
-use Drupal\Core\Entity\EntityFormController;
-use Drupal\Core\Entity\EntityControllerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-
-/**
- * Form controller for node type forms.
- */
-class NodeTypeFormController extends EntityFormController implements EntityControllerInterface {
-
-  /**
-   * The module handler service.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface
-   */
-  protected $moduleHandler;
-
-  /**
-   * Constructs a NodeTypeFormController object.
-   *
-   * @param string $operation
-   *   The name of the current operation.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler to invoke hooks on.
-   */
-  public function __construct($operation, ModuleHandlerInterface $module_handler) {
-    parent::__construct($operation);
-    $this->moduleHandler = $module_handler;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info, $operation = NULL) {
-    return new static(
-      $operation,
-      $container->get('module_handler')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function form(array $form, array &$form_state) {
-    $form = parent::form($form, $form_state);
-
-    $type = $this->entity;
-    if ($this->operation == 'add') {
-      drupal_set_title(t('Add content type'));
-    }
-    elseif ($this->operation == 'edit') {
-      drupal_set_title(t('Edit %label content type', array('%label' => $type->label())), PASS_THROUGH);
-    }
-
-    $node_settings = $type->getModuleSettings('node');
-    // Ensure default settings.
-    $node_settings += array(
-      'options' => array('status', 'promote'),
-      'preview' => DRUPAL_OPTIONAL,
-      'submitted' => TRUE,
-    );
-
-    $form['name'] = array(
-      '#title' => t('Name'),
-      '#type' => 'textfield',
-      '#default_value' => $type->name,
-      '#description' => t('The human-readable name of this content type. This text will be displayed as part of the list on the <em>Add new content</em> page. It is recommended that this name begin with a capital letter and contain only letters, numbers, and spaces. This name must be unique.'),
-      '#required' => TRUE,
-      '#size' => 30,
-    );
-
-    $form['type'] = array(
-      '#type' => 'machine_name',
-      '#default_value' => $type->id(),
-      '#maxlength' => 32,
-      '#disabled' => $type->isLocked(),
-      '#machine_name' => array(
-        'exists' => 'node_type_load',
-        'source' => array('name'),
-      ),
-      '#description' => t('A unique machine-readable name for this content type. It must only contain lowercase letters, numbers, and underscores. This name will be used for constructing the URL of the %node-add page, in which underscores will be converted into hyphens.', array(
-        '%node-add' => t('Add new content'),
-      )),
-    );
-
-    $form['description'] = array(
-      '#title' => t('Description'),
-      '#type' => 'textarea',
-      '#default_value' => $type->description,
-      '#description' => t('Describe this content type. The text will be displayed on the <em>Add new content</em> page.'),
-    );
-
-    $form['additional_settings'] = array(
-      '#type' => 'vertical_tabs',
-      '#attached' => array(
-        'library' => array(array('node', 'drupal.content_types')),
-      ),
-    );
-
-    $form['submission'] = array(
-      '#type' => 'details',
-      '#title' => t('Submission form settings'),
-      '#group' => 'additional_settings',
-    );
-    $form['submission']['title_label'] = array(
-      '#title' => t('Title field label'),
-      '#type' => 'textfield',
-      '#default_value' => $type->title_label,
-      '#required' => TRUE,
-    );
-    if (!$type->has_title) {
-      // Avoid overwriting a content type that intentionally does not have a
-      // title field.
-      $form['submission']['title_label']['#attributes'] = array('disabled' => 'disabled');
-      $form['submission']['title_label']['#description'] = t('This content type does not have a title field.');
-      $form['submission']['title_label']['#required'] = FALSE;
-    }
-    $form['submission']['preview'] = array(
-      '#type' => 'radios',
-      '#title' => t('Preview before submitting'),
-      '#parents' => array('settings', 'node', 'preview'),
-      '#default_value' => $node_settings['preview'],
-      '#options' => array(
-        DRUPAL_DISABLED => t('Disabled'),
-        DRUPAL_OPTIONAL => t('Optional'),
-        DRUPAL_REQUIRED => t('Required'),
-      ),
-    );
-    $form['submission']['help']  = array(
-      '#type' => 'textarea',
-      '#title' => t('Explanation or submission guidelines'),
-      '#default_value' => $type->help,
-      '#description' => t('This text will be displayed at the top of the page when creating or editing content of this type.'),
-    );
-    $form['workflow'] = array(
-      '#type' => 'details',
-      '#title' => t('Publishing options'),
-      '#collapsed' => TRUE,
-      '#group' => 'additional_settings',
-    );
-    $form['workflow']['options'] = array('#type' => 'checkboxes',
-      '#title' => t('Default options'),
-      '#parents' => array('settings', 'node', 'options'),
-      '#default_value' => $node_settings['options'],
-      '#options' => array(
-        'status' => t('Published'),
-        'promote' => t('Promoted to front page'),
-        'sticky' => t('Sticky at top of lists'),
-        'revision' => t('Create new revision'),
-      ),
-      '#description' => t('Users with the <em>Administer content</em> permission will be able to override these options.'),
-    );
-    if ($this->moduleHandler->moduleExists('language')) {
-      $form['language'] = array(
-        '#type' => 'details',
-        '#title' => t('Language settings'),
-        '#collapsed' => TRUE,
-        '#group' => 'additional_settings',
-      );
-
-      $language_configuration = language_get_default_configuration('node', $type->id());
-      $form['language']['language_configuration'] = array(
-        '#type' => 'language_configuration',
-        '#entity_information' => array(
-          'entity_type' => 'node',
-          'bundle' => $type->id(),
-        ),
-        '#default_value' => $language_configuration,
-      );
-    }
-    $form['display'] = array(
-      '#type' => 'details',
-      '#title' => t('Display settings'),
-      '#collapsed' => TRUE,
-      '#group' => 'additional_settings',
-    );
-    $form['display']['submitted'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Display author and date information.'),
-      '#parents' => array('settings', 'node', 'submitted'),
-      '#default_value' => $node_settings['submitted'],
-      '#description' => t('Author username and publish date will be displayed.'),
-    );
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function actions(array $form, array &$form_state) {
-    $actions = parent::actions($form, $form_state);
-    $actions['submit']['#value'] = t('Save content type');
-    $actions['delete']['#value'] = t('Delete content type');
-    $actions['delete']['#access'] = $this->entity->access('delete');
-    return $actions;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validate(array $form, array &$form_state) {
-    parent::validate($form, $form_state);
-
-    $id = trim($form_state['values']['type']);
-    // '0' is invalid, since elsewhere we check it using empty().
-    if ($id == '0') {
-      form_set_error('type', t("Invalid machine-readable name. Enter a name other than %invalid.", array('%invalid' => $id)));
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function save(array $form, array &$form_state) {
-    $type = $this->entity;
-    $type->type = trim($type->id());
-    $type->name = trim($type->name);
-
-    // title_label is required in core; has_title will always be TRUE, unless a
-    // module alters the title field.
-    $type->has_title = ($type->title_label != '');
-
-    $variables = $form_state['values'];
-
-    // Do not save settings from vertical tabs.
-    // @todo Fix vertical_tabs.
-    unset($variables['additional_settings__active_tab']);
-
-    // @todo Remove the entire following code after converting node settings of
-    //   Comment and Menu module. https://drupal.org/node/2026165
-    // Remove all node type entity properties.
-    foreach (get_class_vars(get_class($type)) as $key => $value) {
-      unset($variables[$key]);
-    }
-    // Save or reset persistent variable values.
-    foreach ($variables as $key => $value) {
-      $variable_new = $key . '_' . $type->id();
-      $variable_old = $key . '_' . $type->getOriginalID();
-      if (is_array($value)) {
-        $value = array_keys(array_filter($value));
-      }
-      variable_set($variable_new, $value);
-      if ($variable_new != $variable_old) {
-        variable_del($variable_old);
-      }
-    }
-    // Saving the content type after saving the variables allows modules to act
-    // on those variables via hook_node_type_insert().
-    $status = $type->save();
-
-    $t_args = array('%name' => $type->label());
-
-    if ($status == SAVED_UPDATED) {
-      drupal_set_message(t('The content type %name has been updated.', $t_args));
-    }
-    elseif ($status == SAVED_NEW) {
-      drupal_set_message(t('The content type %name has been added.', $t_args));
-      watchdog('node', 'Added content type %name.', $t_args, WATCHDOG_NOTICE, l(t('view'), 'admin/structure/types'));
-    }
-
-    $form_state['redirect'] = 'admin/structure/types';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function delete(array $form, array &$form_state) {
-    $form_state['redirect'] = 'admin/structure/types/manage/' . $this->entity->id() . '/delete';
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeInterface.php b/core/modules/node/lib/Drupal/node/NodeTypeInterface.php
deleted file mode 100644
index 691713b..0000000
--- a/core/modules/node/lib/Drupal/node/NodeTypeInterface.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\NodeTypeInterface.
- */
-
-namespace Drupal\node;
-
-use Drupal\Core\Config\Entity\ConfigEntityInterface;
-
-/**
- * Provides an interface defining a node type entity.
- */
-interface NodeTypeInterface extends ConfigEntityInterface {
-
-  /**
-   * Returns the configured node type settings of a given module, if any.
-   *
-   * @param string $module
-   *   The name of the module whose settings to return.
-   *
-   * @return array
-   *   An associative array containing the module's settings for the node type.
-   *   Note that this can be empty, and default values do not necessarily exist.
-   */
-  public function getModuleSettings($module);
-
-  /**
-   * Returns a locked state of the type.
-   *
-   * @return string|false
-   *   The module name that locks the type or FALSE.
-   */
-  public function isLocked();
-
-}
diff --git a/core/modules/node/lib/Drupal/node/NodeTypeListController.php b/core/modules/node/lib/Drupal/node/NodeTypeListController.php
deleted file mode 100644
index 3f51613..0000000
--- a/core/modules/node/lib/Drupal/node/NodeTypeListController.php
+++ /dev/null
@@ -1,125 +0,0 @@
-<?php
-
-/**
- * Contains \Drupal\node\NodeTypeListController.
- */
-
-namespace Drupal\node;
-
-use Drupal\Core\Config\Entity\ConfigEntityListController;
-use Drupal\Core\Entity\EntityControllerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Drupal\Core\Entity\EntityStorageControllerInterface;
-use Drupal\Core\Extension\ModuleHandlerInterface;
-use Drupal\Core\Routing\PathBasedGeneratorInterface;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Component\Utility\Xss;
-use Drupal\Component\Utility\String;
-
-/**
- * Provides a listing of node types.
- */
-class NodeTypeListController extends ConfigEntityListController implements EntityControllerInterface {
-
-  /**
-   * The url generator service.
-   *
-   * @var \Drupal\Core\Routing\PathBasedGeneratorInterface
-   */
-  protected $urlGenerator;
-
-  /**
-   * Constructs a NodeTypeFormController object.
-   *
-   * @param string $entity_type
-   *   The type of entity to be listed.
-   * @param array $entity_info
-   *   An array of entity info for the entity type.
-   * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage
-   *   The entity storage controller class.
-   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
-   *   The module handler to invoke hooks on.
-   * @param \Drupal\Core\Routing\PathBasedGeneratorInterface $url_generator
-   *   The url generator service.
-   */
-  public function __construct($entity_type, array $entity_info, EntityStorageControllerInterface $storage, ModuleHandlerInterface $module_handler, PathBasedGeneratorInterface $url_generator) {
-    parent::__construct($entity_type, $entity_info, $storage, $module_handler);
-    $this->urlGenerator = $url_generator;
-  }
-  /**
-   * {@inheritdoc}
-   */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
-    return new static(
-      $entity_type,
-      $entity_info,
-      $container->get('plugin.manager.entity')->getStorageController($entity_type),
-      $container->get('module_handler'),
-      $container->get('url_generator')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildHeader() {
-    $row['title'] = t('Name');
-    $row['description'] = array(
-      'data' => t('Description'),
-      'class' => array(RESPONSIVE_PRIORITY_MEDIUM),
-    );
-    $row['operations'] = t('Operations');
-    return $row;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildRow(EntityInterface $entity) {
-    $row['title'] = array(
-      'data' => String::checkPlain($entity->label()),
-      'class' => array('menu-label'),
-    );
-    $row['description'] = Xss::filterAdmin($entity->description);
-    $row['operations']['data'] = $this->buildOperations($entity);
-    return $row;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    if ($this->moduleHandler->moduleExists('field_ui') && user_access('administer node fields')) {
-      $uri = $entity->uri();
-      $operations['manage-fields'] = array(
-        'title' => t('Manage fields'),
-        'href' => $uri['path'] . '/fields',
-        'options' => $uri['options'],
-        'weight' => 0,
-      );
-      $operations['manage-display'] = array(
-        'title' => t('Manage display'),
-        'href' => $uri['path'] . '/display',
-        'options' => $uri['options'],
-        'weight' => 5,
-      );
-    }
-    if ($entity->isLocked()) {
-      unset($operations['delete']);
-    }
-    return $operations;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function render() {
-    $build = parent::render();
-    $build['#empty'] = t('No content types available. <a href="@link">Add content type</a>.', array(
-      '@link' => $this->urlGenerator->generateFromPath('admin/structure/types/add'),
-    ));
-    return $build;
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/NodeType.php b/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/NodeType.php
deleted file mode 100644
index 464fbe0..0000000
--- a/core/modules/node/lib/Drupal/node/Plugin/Core/Entity/NodeType.php
+++ /dev/null
@@ -1,218 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Plugin\Core\Entity\NodeType.
- */
-
-namespace Drupal\node\Plugin\Core\Entity;
-
-use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\Core\Entity\EntityStorageControllerInterface;
-use Drupal\node\NodeTypeInterface;
-use Drupal\Core\Entity\Annotation\EntityType;
-use Drupal\Core\Annotation\Translation;
-
-/**
- * Defines the Node type configuration entity.
- *
- * @EntityType(
- *   id = "node_type",
- *   label = @Translation("Content type"),
- *   module = "node",
- *   controllers = {
- *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
- *     "access" = "Drupal\node\NodeTypeAccessController",
- *     "form" = {
- *       "add" = "Drupal\node\NodeTypeFormController",
- *       "edit" = "Drupal\node\NodeTypeFormController",
- *       "delete" = "Drupal\node\Form\NodeTypeDeleteConfirm"
- *     },
- *     "list" = "Drupal\node\NodeTypeListController",
- *   },
- *   config_prefix = "node.type",
- *   entity_keys = {
- *     "id" = "type",
- *     "label" = "name",
- *     "uuid" = "uuid"
- *   }
- * )
- */
-class NodeType extends ConfigEntityBase implements NodeTypeInterface {
-
-  /**
-   * The machine name of this node type.
-   *
-   * @var string
-   *
-   * @todo Rename to $id.
-   */
-  public $type;
-
-  /**
-   * The UUID of the node type.
-   *
-   * @var string
-   */
-  public $uuid;
-
-  /**
-   * The human-readable name of the node type.
-   *
-   * @var string
-   *
-   * @todo Rename to $label.
-   */
-  public $name;
-
-  /**
-   * A brief description of this node type.
-   *
-   * @var string
-   */
-  public $description;
-
-  /**
-   * Help information shown to the user when creating a Node of this type.
-   *
-   * @var string
-   */
-  public $help;
-
-  /**
-   * Indicates whether the Node entity of this type has a title.
-   *
-   * @var bool
-   *
-   * @todo Rename to $node_has_title.
-   */
-  public $has_title = TRUE;
-
-  /**
-   * The label to use for the title of a Node of this type in the user interface.
-   *
-   * @var string
-   *
-   * @todo Rename to $node_title_label.
-   */
-  public $title_label = 'Title';
-
-  /**
-   * Indicates whether a Body field should be created for this node type.
-   *
-   * This property affects entity creation only. It allows default configuration
-   * of modules and installation profiles to specify whether a Body field should
-   * be created for this bundle.
-   *
-   * @var bool
-   *
-   * @see \Drupal\node\Plugin\Core\Entity\NodeType::$create_body_label
-   */
-  protected $create_body = TRUE;
-
-  /**
-   * The label to use for the Body field upon entity creation.
-   *
-   * @see \Drupal\node\Plugin\Core\Entity\NodeType::$create_body
-   *
-   * @var string
-   */
-  protected $create_body_label = 'Body';
-
-  /**
-   * Module-specific settings for this node type, keyed by module name.
-   *
-   * @var array
-   *
-   * @todo Pluginify.
-   */
-  public $settings = array();
-
-  /**
-   * {@inheritdoc}
-   */
-  public function id() {
-    return $this->type;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function uri() {
-    return array(
-      'path' => 'admin/structure/types/manage/' . $this->id(),
-      'options' => array(
-        'entity_type' => $this->entityType,
-        'entity' => $this,
-      ),
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getModuleSettings($module) {
-    if (isset($this->settings[$module]) && is_array($this->settings[$module])) {
-      return $this->settings[$module];
-    }
-    return array();
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function isLocked() {
-    $locked = \Drupal::state()->get('node.type.locked');
-    return isset($locked[$this->id()]) ? $locked[$this->id()] : FALSE;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function postSave(EntityStorageControllerInterface $storage_controller, $update = TRUE) {
-    if (!$update) {
-      // Clear the node type cache, so the new type appears.
-      \Drupal::cache()->deleteTags(array('node_types' => TRUE));
-
-      entity_invoke_bundle_hook('create', 'node', $this->id());
-
-      // Unless disabled, automatically create a Body field for new node types.
-      if ($this->get('create_body')) {
-        $label = $this->get('create_body_label');
-        node_add_body_field($this, $label);
-      }
-    }
-    elseif ($this->getOriginalID() != $this->id()) {
-      // Clear the node type cache to reflect the rename.
-      \Drupal::cache()->deleteTags(array('node_types' => TRUE));
-
-      $update_count = node_type_update_nodes($this->getOriginalID(), $this->id());
-      if ($update_count) {
-        drupal_set_message(format_plural($update_count,
-          'Changed the content type of 1 post from %old-type to %type.',
-          'Changed the content type of @count posts from %old-type to %type.',
-          array(
-            '%old-type' => $this->getOriginalID(),
-            '%type' => $this->id(),
-          )));
-      }
-      entity_invoke_bundle_hook('rename', 'node', $this->getOriginalID(), $this->id());
-    }
-    else {
-      // Invalidate the cache tag of the updated node type only.
-      cache()->invalidateTags(array('node_type' => $this->id()));
-    }
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function postDelete(EntityStorageControllerInterface $storage_controller, array $entities) {
-    // Clear the node type cache to reflect the removal.
-    $storage_controller->resetCache(array_keys($entities));
-    foreach ($entities as $entity) {
-      entity_invoke_bundle_hook('delete', 'node', $entity->id());
-    }
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php b/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php
index d06040a..9d93846 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/argument/Type.php
@@ -33,9 +33,11 @@ function title() {
     return $this->node_type($this->argument);
   }
 
-  function node_type($type_name) {
-    $type = entity_load('node_type', $type_name);
-    $output = $type ? $type->label() : t('Unknown content type');
+  function node_type($type) {
+    $output = node_type_get_label($type);
+    if (empty($output)) {
+      $output = t('Unknown content type');
+    }
     return check_plain($output);
   }
 
diff --git a/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php b/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php
index 6d31ae4..5a6c25f 100644
--- a/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php
+++ b/core/modules/node/lib/Drupal/node/Plugin/views/field/Type.php
@@ -45,8 +45,7 @@ public function buildOptionsForm(&$form, &$form_state) {
     */
   function render_name($data, $values) {
     if ($this->options['machine_name'] != 1 && $data !== NULL && $data !== '') {
-      $type = entity_load('node_type', $data);
-      return $type ? t($this->sanitizeValue($type->label())) : '';
+      return t($this->sanitizeValue(node_type_get_label($data)));
     }
     return $this->sanitizeValue($data);
   }
diff --git a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
index 31d515f..c5856e5 100644
--- a/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/Condition/NodeConditionTest.php
@@ -26,6 +26,7 @@ public static function getInfo() {
 
   protected function setUp() {
     parent::setUp();
+    $this->installSchema('node', 'node_type');
     $this->installSchema('node', 'node');
     $this->installSchema('node', 'node_field_data');
     $this->installSchema('node', 'node_field_revision');
diff --git a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportChangeTest.php b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportChangeTest.php
deleted file mode 100644
index 8f162e0..0000000
--- a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportChangeTest.php
+++ /dev/null
@@ -1,71 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Tests\Config\NodeImportChangeTest.
- */
-
-namespace Drupal\node\Tests\Config;
-
-use Drupal\simpletest\DrupalUnitTestBase;
-
-/**
- * Tests updating content types as part of config import.
- */
-class NodeImportChangeTest extends DrupalUnitTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('node', 'entity', 'field', 'text', 'field_sql_storage', 'system', 'node_test_config');
-
-  /**
-   * Set the default field storage backend for fields created during tests.
-   */
-  public function setUp() {
-    parent::setUp();
-
-    $this->installSchema('system', array('config_snapshot'));
-
-    // Set default storage backend.
-    $this->installConfig(array('field', 'node_test_config'));
-  }
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Node config change tests',
-      'description' => 'Change content types during config create method invocation.',
-      'group' => 'Node',
-    );
-  }
-
-  /**
-   * Tests importing an updated content type.
-   */
-  public function testImportChange() {
-    $node_type_id = 'default';
-    $node_type_config_name = "node.type.$node_type_id";
-
-    // Simulate config data to import:
-    // - a modified version (modified label) of the node type config.
-    $active = $this->container->get('config.storage');
-    $staging = $this->container->get('config.storage.staging');
-    $this->copyConfig($active, $staging);
-
-    $node_type = $active->read($node_type_config_name);
-    $new_label = 'Test update import field';
-    $node_type['name'] = $new_label;
-    // Save as files in the the staging directory.
-    $staging->write($node_type_config_name, $node_type);
-
-    // Import the content of the staging directory.
-    $this->configImporter()->import();
-
-    // Check that the updated config was correctly imported.
-    $node_type = entity_load('node_type', $node_type_id);
-    $this->assertEqual($node_type->label(), $new_label, 'Node type name has been updated.');
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php b/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php
deleted file mode 100644
index 593093a..0000000
--- a/core/modules/node/lib/Drupal/node/Tests/Config/NodeImportCreateTest.php
+++ /dev/null
@@ -1,83 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\node\Tests\Config\NodeImportCreateTest.
- */
-
-namespace Drupal\node\Tests\Config;
-
-use Drupal\simpletest\DrupalUnitTestBase;
-
-/**
- * Tests content types as part of config import.
- */
-class NodeImportCreateTest extends DrupalUnitTestBase {
-
-  /**
-   * Modules to enable.
-   *
-   * @var array
-   */
-  public static $modules = array('node', 'entity', 'field', 'text', 'field_sql_storage', 'system');
-
-  /**
-   * Set the default field storage backend for fields created during tests.
-   */
-  public function setUp() {
-    parent::setUp();
-
-    $this->installSchema('system', array('config_snapshot'));
-
-    // Set default storage backend.
-    $this->installConfig(array('field'));
-  }
-
-  public static function getInfo() {
-    return array(
-      'name' => 'Node config create tests',
-      'description' => 'Create content types during config create method invocation.',
-      'group' => 'Node',
-    );
-  }
-
-  /**
-   * Tests creating a content type during default config import.
-   */
-  public function testImportCreateDefault() {
-    $node_type_id = 'default';
-
-    // Check that the content type does not exist yet.
-    $this->assertFalse(entity_load('node_type', $node_type_id));
-
-    // Enable node_test_config module and check that the content type
-    // shipped in the module's default config is created.
-    $this->container->get('module_handler')->enable(array('node_test_config'));
-    $node_type = entity_load('node_type', $node_type_id);
-    $this->assertTrue($node_type, 'The default content type was created.');
-  }
-
-  /**
-   * Tests creating a content type during config import.
-   */
-  public function testImportCreate() {
-    $node_type_id = 'import';
-    $node_type_config_name = "node.type.$node_type_id";
-
-    // Simulate config data to import.
-    $active = $this->container->get('config.storage');
-    $staging = $this->container->get('config.storage.staging');
-    $this->copyConfig($active, $staging);
-    // Manually add new node type.
-    $src_dir = drupal_get_path('module', 'node_test_config') . '/staging';
-    $this->assertTrue(file_unmanaged_copy("$src_dir/$node_type_config_name.yml", "public://config_staging/$node_type_config_name.yml"));
-
-    // Import the content of the staging directory.
-    $this->configImporter()->import();
-
-    // Check that the content type was created.
-    $node_type = entity_load('node_type', $node_type_id);
-    $this->assertTrue($node_type, 'Import node type from staging was created.');
-  }
-
-}
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php
index 55719bb..f531520 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeCreationTest.php
@@ -107,7 +107,7 @@ function testUnpublishedNodeCreation() {
     config('system.site')->set('page.front', 'test-page')->save();
 
     // Set "Basic page" content type to be unpublished by default.
-    config('node.type.page')->set('settings.node.options', array())->save();
+    variable_set('node_options_page', array());
 
     // Create a node.
     $edit = array();
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php
index a592c88..a2bd56c 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeFormButtonsTest.php
@@ -109,7 +109,7 @@ function testNodeFormButtons() {
     // the initial order of buttons and/or status of the node when creating
     // a node.
     variable_set('node_options_article', array('promote'));
-    config('node.type.article')->set('settings.node.options.status', 0)->save();
+    $this->refreshVariables();
 
     // Verify the buttons on a node add form for an administrator.
     $this->drupalLogin($this->admin_user);
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php b/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php
index a1f3a75..c72dc25 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodePostSettingsTest.php
@@ -36,7 +36,7 @@ function testPagePostInfo() {
 
     // Set "Basic page" content type to display post information.
     $edit = array();
-    $edit['settings[node][submitted]'] = TRUE;
+    $edit['node_submitted'] = TRUE;
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
 
     // Create a node.
@@ -50,11 +50,16 @@ function testPagePostInfo() {
     $node = $this->drupalGetNodeByTitle($edit["title"]);
     $elements = $this->xpath('//*[contains(@class,:class)]', array(':class' => 'submitted'));
     $this->assertEqual(count($elements), 1, 'Post information is displayed.');
-    $node->delete();
+  }
+
+  /**
+   * Confirms absence of post information on a new node.
+   */
+  function testPageNotPostInfo() {
 
     // Set "Basic page" content type to display post information.
     $edit = array();
-    $edit['settings[node][submitted]'] = FALSE;
+    $edit['node_submitted'] = FALSE;
     $this->drupalPost('admin/structure/types/manage/page', $edit, t('Save content type'));
 
     // Create a node.
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php
index 22aedb4..d8fa419 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypePersistenceTest.php
@@ -31,11 +31,12 @@ function testNodeTypeCustomizationPersistence() {
     $forum_enable = array($forum_key => "1");
     $forum_disable = array($forum_key => FALSE);
 
-    // Enable forum and verify that the node type exists and is not disabled.
+    // Enable forum and verify that the node type is in the DB and is not
+    // disabled.
     $this->drupalPost('admin/modules', $forum_enable, t('Save configuration'));
-    $forum = entity_load('node_type', 'forum');
-    $this->assertTrue($forum->id(), 'Forum node type found.');
-    $this->assertTrue($forum->isLocked(), 'Forum node type is locked');
+    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
+    $this->assertNotIdentical($disabled, FALSE, 'Forum node type found in the database');
+    $this->assertEqual($disabled, 0, 'Forum node type is not disabled');
 
     // Check that forum node type (uncustomized) shows up.
     $this->drupalGet('node/add');
@@ -52,17 +53,17 @@ function testNodeTypeCustomizationPersistence() {
 
     // Disable forum and check that the node type gets disabled.
     $this->drupalPost('admin/modules', $forum_disable, t('Save configuration'));
-    $forum = entity_load('node_type', 'forum');
-    $this->assertTrue($forum->isLocked(), 'Forum node type is node locked');
+    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
+    $this->assertEqual($disabled, 1, 'Forum node type is disabled');
     $this->drupalGet('node/add');
     $this->assertNoText('forum', 'forum type is not found on node/add');
 
     // Reenable forum and check that the customization survived the module
     // disable.
     $this->drupalPost('admin/modules', $forum_enable, t('Save configuration'));
-    $forum = entity_load('node_type', 'forum');
-    $this->assertTrue($forum->id(), 'Forum node type found.');
-    $this->assertTrue($forum->isLocked(), 'Forum node type is locked');
+    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
+    $this->assertNotIdentical($disabled, FALSE, 'Forum node type found in the database');
+    $this->assertEqual($disabled, 0, 'Forum node type is not disabled');
     $this->drupalGet('node/add');
     $this->assertText($description, 'Customized description found');
 
@@ -71,8 +72,8 @@ function testNodeTypeCustomizationPersistence() {
     $edit = array('uninstall[forum]' => 'forum');
     $this->drupalPost('admin/modules/uninstall', $edit, t('Uninstall'));
     $this->drupalPost(NULL, array(), t('Uninstall'));
-    $forum = entity_load('node_type', 'forum');
-    $this->assertFalse($forum->isLocked(), 'Forum node type is not locked');
+    $disabled = db_query('SELECT disabled FROM {node_type} WHERE type = :type', array(':type' => 'forum'))->fetchField();
+    $this->assertTrue($disabled, 'Forum node type is in the database and is disabled');
     $this->drupalGet('node/add');
     $this->assertNoText('forum', 'forum type is no longer found on node/add');
 
@@ -82,5 +83,4 @@ function testNodeTypeCustomizationPersistence() {
     $this->drupalGet('node/add');
     $this->assertText($description, 'Customized description is found even after uninstall and reenable.');
   }
-
 }
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
index f3307e7..6a5b5f6 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTypeTest.php
@@ -41,9 +41,9 @@ function testNodeTypeGetFunctions() {
 
     $this->assertEqual($node_types['article']->name, $node_names['article'], 'Correct node type base has been returned.');
 
-    $article = entity_load('node_type', 'article');
-    $this->assertEqual($node_types['article'], $article, 'Correct node type has been returned.');
-    $this->assertEqual($node_types['article']->name, $article->label(), 'Correct node type name has been returned.');
+    $this->assertEqual($node_types['article'], node_type_load('article'), 'Correct node type has been returned.');
+    $this->assertEqual($node_types['article']->name, node_type_get_label('article'), 'Correct node type name has been returned.');
+    $this->assertEqual($node_types['page']->base, node_type_get_base('page'), 'Correct node type base has been returned.');
   }
 
   /**
@@ -53,7 +53,7 @@ function testNodeTypeCreation() {
     // Create a content type programmaticaly.
     $type = $this->drupalCreateContentType();
 
-    $type_exists = (bool) entity_load('node_type', $type->type);
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => $type->type))->fetchField();
     $this->assertTrue($type_exists, 'The new content type has been created in the database.');
 
     // Login a test user.
@@ -72,7 +72,7 @@ function testNodeTypeCreation() {
       'type' => 'foo',
     );
     $this->drupalPost('admin/structure/types/add', $edit, t('Save content type'));
-    $type_exists = (bool) entity_load('node_type', 'foo');
+    $type_exists = db_query('SELECT 1 FROM {node_type} WHERE type = :type', array(':type' => 'foo'))->fetchField();
     $this->assertTrue($type_exists, 'The new content type has been created in the database.');
   }
 
@@ -130,31 +130,34 @@ function testNodeTypeEditing() {
   }
 
   /**
-   * Tests that node types correctly handles their locking.
+   * Tests that node_types_rebuild() correctly handles the 'disabled' flag.
    */
   function testNodeTypeStatus() {
     // Enable all core node modules, and all types should be active.
-    $this->container->get('module_handler')->enable(array('book'), FALSE);
+    module_enable(array('book'), FALSE);
+    node_types_rebuild();
     $types = node_type_get_types();
     foreach (array('book', 'article', 'page') as $type) {
       $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type)));
-      $this->assertFalse($types[$type]->isLocked(), format_string('%type type is not locked.', array('%type' => $type)));
+      $this->assertTrue(isset($types[$type]->disabled) && empty($types[$type]->disabled), format_string('%type type is enabled.', array('%type' => $type)));
     }
 
     // Disable book module and the respective type should still be active, since
-    // it is not provided by shipped configuration entity.
-    $this->container->get('module_handler')->disable(array('book'), FALSE);
+    // it is not provided by hook_node_info().
+    module_disable(array('book'), FALSE);
+    node_types_rebuild();
     $types = node_type_get_types();
-    $this->assertFalse($types['book']->isLocked(), "Book module's node type still active.");
-    $this->assertFalse($types['article']->isLocked(), 'Article node type still active.');
-    $this->assertFalse($types['page']->isLocked(), 'Basic page node type still active.');
+    $this->assertTrue(isset($types['book']) && empty($types['book']->disabled), "Book module's node type still active.");
+    $this->assertTrue(isset($types['article']) && empty($types['article']->disabled), 'Article node type still active.');
+    $this->assertTrue(isset($types['page']) && empty($types['page']->disabled), 'Basic page node type still active.');
 
     // Re-enable the modules and verify that the types are active again.
-    $this->container->get('module_handler')->enable(array('book'), FALSE);
+    module_enable(array('book'), FALSE);
+    node_types_rebuild();
     $types = node_type_get_types();
     foreach (array('book', 'article', 'page') as $type) {
       $this->assertTrue(isset($types[$type]), format_string('%type is found in node types.', array('%type' => $type)));
-      $this->assertFalse($types[$type]->isLocked(), format_string('%type type is not locked.', array('%type' => $type)));
+      $this->assertTrue(isset($types[$type]->disabled) && empty($types[$type]->disabled), format_string('%type type is enabled.', array('%type' => $type)));
     }
   }
 
@@ -191,14 +194,6 @@ function testNodeTypeDeletion() {
       'The content type is available for deletion.'
     );
     $this->assertText(t('This action cannot be undone.'), 'The node type deletion confirmation form is available.');
-    // Test that forum node type could not be deleted while forum active.
-    $this->container->get('module_handler')->enable(array('forum'));
-    $this->drupalGet('admin/structure/types/manage/forum/delete');
-    $this->assertResponse(403);
-    $this->container->get('module_handler')->disable(array('forum'));
-    $this->container->get('module_handler')->uninstall(array('forum'));
-    $this->drupalGet('admin/structure/types/manage/forum/delete');
-    $this->assertResponse(200);
   }
 
 }
diff --git a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
index b485545..ae7529b 100644
--- a/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
+++ b/core/modules/node/lib/Drupal/node/Tests/PagePreviewTest.php
@@ -186,7 +186,7 @@ function testPagePreviewWithRevisions() {
     $body_key = "body[$langcode][0][value]";
     $term_key = "{$this->field_name}[$langcode]";
     // Force revision on "Basic page" content.
-    $this->container->get('config.factory')->get('node.type.page')->set('settings.node.options', array('status', 'revision'))->save();
+    variable_set('node_options_page', array('status', 'revision'));
 
     // Fill in node creation form and preview node.
     $edit = array();
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 3e0cf3c..2214746 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -14,7 +14,7 @@
  *
  * Each content type is maintained by a primary module, which is either
  * node.module (for content types created in the user interface) or the module
- * that defines the content type by providing configuration file.
+ * that implements hook_node_info() to define the content type.
  *
  * During node operations (create, insert, update, view, delete, etc.), there
  * are several sets of hooks that get invoked to allow modules to modify the
@@ -844,6 +844,62 @@ function hook_node_view_alter(&$build, \Drupal\Core\Entity\EntityInterface $node
 }
 
 /**
+ * Define module-provided node types.
+ *
+ * This hook allows a module to define one or more of its own node types. For
+ * example, the forum module uses it to define a forum node-type named "Forum
+ * topic." The name and attributes of each desired node type are specified in an
+ * array returned by the hook.
+ *
+ * Only module-provided node types should be defined through this hook. User-
+ * provided (or 'custom') node types should be defined only in the 'node_type'
+ * database table, and should be maintained by using the node_type_save() and
+ * node_type_delete() functions.
+ *
+ * @return
+ *   An array of information defining the module's node types. The array
+ *   contains a sub-array for each node type, with the the machine name of a
+ *   content type as the key. Each sub-array has up to 10 attributes.
+ *   Possible attributes:
+ *   - name: (required) The human-readable name of the node type.
+ *   - base: (required) The base string used to construct callbacks
+ *     corresponding to this node type (for example, if base is defined as
+ *     example_foo, then example_foo_insert will be called when inserting a node
+ *     of that type). This string is usually the name of the module, but not
+ *     always.
+ *   - description: (required) A brief description of the node type.
+ *   - help: (optional) Help information shown to the user when creating a node
+ *     of this type.
+ *   - has_title: (optional) A Boolean indicating whether or not this node type
+ *     has a title field.
+ *   - title_label: (optional) The label for the title field of this content
+ *     type.
+ *   - locked: (optional) A Boolean indicating whether the administrator can
+ *     change the machine name of this type. FALSE = changeable (not locked),
+ *     TRUE = unchangeable (locked).
+ *
+ * The machine name of a node type should contain only letters, numbers, and
+ * underscores. Underscores will be converted into hyphens for the purpose of
+ * constructing URLs.
+ *
+ * All attributes of a node type that are defined through this hook (except for
+ * 'locked') can be edited by a site administrator. This includes the
+ * machine-readable name of a node type, if 'locked' is set to FALSE.
+ *
+ * @ingroup node_api_hooks
+ */
+function hook_node_info() {
+  return array(
+    'forum' => array(
+      'name' => t('Forum topic'),
+      'base' => 'forum',
+      'description' => t('A <em>forum topic</em> starts a new discussion thread within a forum.'),
+      'title_label' => t('Subject'),
+    )
+  );
+}
+
+/**
  * Provide additional methods of scoring for core search results for nodes.
  *
  * A node's search score is used to rank it among other nodes matched by the
@@ -908,33 +964,44 @@ function hook_ranking() {
 /**
  * Respond to node type creation.
  *
- * @param \Drupal\node\NodeTypeInterface $type
- *   The node type entity that was created.
+ * This hook is invoked from node_type_save() after the node type is added to
+ * the database.
+ *
+ * @param $info
+ *   The node type object that is being created.
  */
-function hook_node_type_insert(\Drupal\node\NodeTypeInterface $type) {
-  drupal_set_message(t('You have just created a content type with a machine name %type.', array('%type' => $type->id())));
+function hook_node_type_insert($info) {
+  drupal_set_message(t('You have just created a content type with a machine name %type.', array('%type' => $info->type)));
 }
 
 /**
  * Respond to node type updates.
  *
- * @param \Drupal\node\NodeTypeInterface $type
- *   The node type entity that was updated.
+ * This hook is invoked from node_type_save() after the node type is updated in
+ * the database.
+ *
+ * @param $info
+ *   The node type object that is being updated.
  */
-function hook_node_type_update(\Drupal\node\NodeTypeInterface $type) {
-  if ($type->original->id() != $type->id()) {
-    drupal_set_message(t('You have just changed the machine name of a content type from %old_type to %type.', array('%old_type' => $type->original->id(), '%type' => $type->id())));
+function hook_node_type_update($info) {
+  if (!empty($info->old_type) && $info->old_type != $info->type) {
+    $setting = variable_get('comment_' . $info->old_type, COMMENT_NODE_OPEN);
+    variable_del('comment_' . $info->old_type);
+    variable_set('comment_' . $info->type, $setting);
   }
 }
 
 /**
  * Respond to node type deletion.
  *
- * @param \Drupal\node\NodeTypeInterface $type
- *   The node type entity that was deleted.
+ * This hook is invoked from node_type_delete() after the node type is removed
+ * from the database.
+ *
+ * @param $info
+ *   The node type object that is being deleted.
  */
-function hook_node_type_delete(\Drupal\node\NodeTypeInterface $type) {
-  drupal_set_message(t('You have just deleted a content type with the machine name %type.', array('%type' => $type->id())));
+function hook_node_type_delete($info) {
+  variable_del('comment_' . $info->type);
 }
 
 /**
diff --git a/core/modules/node/node.install b/core/modules/node/node.install
index d16b875..0c545b3 100644
--- a/core/modules/node/node.install
+++ b/core/modules/node/node.install
@@ -5,7 +5,6 @@
  * Install, update and uninstall functions for the node module.
  */
 
-use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
 
 /**
@@ -37,7 +36,7 @@ function node_schema() {
         'default' => NULL,
       ),
       'type' => array(
-        'description' => 'The type of this node.',
+        'description' => 'The {node_type}.type of this node.',
         'type' => 'varchar',
         'length' => 32,
         'not null' => TRUE,
@@ -388,6 +387,100 @@ function node_schema() {
     ),
   );
 
+  $schema['node_type'] = array(
+    'description' => 'Stores information about all defined {node} types.',
+    'fields' => array(
+      'type' => array(
+        'description' => 'The machine-readable name of this type.',
+        'type' => 'varchar',
+        'length' => 32,
+        'not null' => TRUE,
+      ),
+      'name' => array(
+        'description' => 'The human-readable name of this type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'base' => array(
+        'description' => 'The base string used to construct callbacks corresponding to this node type.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'module' => array(
+        'description' => 'The module defining this node type.',
+        'type' => 'varchar',
+        'length' => DRUPAL_EXTENSION_NAME_MAX_LENGTH,
+        'not null' => TRUE,
+      ),
+      'description' => array(
+        'description' => 'A brief description of this type.',
+        'type' => 'text',
+        'not null' => TRUE,
+        'size' => 'medium',
+      ),
+      'help' => array(
+        'description' => 'Help information shown to the user when creating a {node} of this type.',
+        'type' => 'text',
+        'not null' => TRUE,
+        'size' => 'medium',
+      ),
+      'has_title' => array(
+        'description' => 'Boolean indicating whether this type uses the {node}.title field.',
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'size' => 'tiny',
+      ),
+      'title_label' => array(
+        'description' => 'The label displayed for the title field on the edit form.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+      'custom' => array(
+        'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via Add content type (TRUE).',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'modified' => array(
+        'description' => 'A boolean indicating whether this type has been modified by an administrator; currently not used in any way.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'locked' => array(
+        'description' => 'A boolean indicating whether the administrator can change the machine name of this type.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'disabled' => array(
+        'description' => 'A boolean indicating whether the node type is disabled.',
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+      ),
+      'orig_type' => array(
+        'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+        'default' => '',
+      ),
+    ),
+    'primary key' => array('type'),
+  );
+
+
   return $schema;
 }
 
@@ -416,9 +509,17 @@ function node_install() {
  */
 function node_uninstall() {
   // Delete node type variables.
-  $types = config_get_storage_names_with_prefix('node.type.');
-  foreach ($types as $config_name) {
-    $type = config($config_name)->get('type');
+  $types = db_query('SELECT type FROM {node_type}')->fetchCol();
+  foreach ($types as $type) {
+    db_delete('variable')
+      ->condition(db_or()
+        ->condition('name', 'node_preview_' . $type)
+        ->condition('name', 'node_options_' . $type)
+        ->condition('name', 'node_submitted_' . $type)
+        ->condition('name', 'node_permissions_' . $type)
+        ->condition('name', 'node_type_language_translation_enabled_' . $type)
+      )
+      ->execute();
     config('language.settings')->clear('node. ' . $type . '.language.default_configuration')->save();
   }
 
@@ -1064,57 +1165,6 @@ function node_update_8019() {
 }
 
 /**
- * Convert node types into configuration.
- *
- * @ingroup config_upgrade
-*/
-function node_update_8020() {
-  $uuid = new Uuid();
-  // Properties to drop: custom, disabled.
-  $locked = array();
-  // Note: {node_type}.name was the label, .type the machine name.
-  $result = db_query('SELECT * FROM {node_type}')
-    ->fetchAllAssoc('type', PDO::FETCH_ASSOC);
-  foreach ($result as $id => $node_type) {
-    $config = config('node.type.' . $id);
-    // Node type.
-    $config->setData($node_type);
-    $config->set('uuid', $uuid->generate());
-    $config->set('langcode', Language::LANGCODE_NOT_SPECIFIED);
-
-    // Node type settings.
-    $variables = db_query('SELECT name, value FROM {variable} WHERE name IN (:names)', array(
-      ':names' => array(
-        'node_submitted_' . $id,
-        'node_preview_' . $id,
-        'node_options_' . $id,
-      ),
-    ))->fetchAllKeyed();
-    $variables = array_map('unserialize', $variables);
-    // There are not necessarily values for all settings, so pollute defaults.
-    $variables += array(
-      'node_submitted_' . $id => TRUE,
-      'node_preview_' . $id => 1, // DRUPAL_OPTIONAL
-      'node_options_' . $id => array('status', 'promote'),
-    );
-    foreach ($variables as $name => $value) {
-      // Turn e.g. 'node_submitted_ID' into 'submitted'.
-      $name = str_replace(array('node_', '_' . $id), '', $name);
-      $config->set('settings.node.' . $name, $value);
-
-      update_variable_del($name);
-    }
-    $config->save();
-    // Convert the 'base' property to state. Note that we could have disabled
-    // modules at this time but we still need to preserve the relation.
-    if ($node_type['base'] !== 'node_content') {
-      $locked[$id] = $node_type['base'];
-    }
-  }
-  Drupal::state()->set('node.type.locked', $locked);
-}
-
-/**
  * @} End of "addtogroup updates-7.x-to-8.x"
  * The next series of updates should start at 9000.
  */
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 1730572..fbdf07d 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -16,7 +16,6 @@
 use Drupal\Core\Database\Query\SelectExtender;
 use Drupal\Core\Database\Query\SelectInterface;
 use Drupal\Core\Datetime\DrupalDateTime;
-use Drupal\node\NodeTypeInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Template\Attribute;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
@@ -78,6 +77,13 @@
 const NODE_ACCESS_IGNORE = NULL;
 
 /**
+ * Implements hook_rebuild().
+ */
+function node_rebuild() {
+  node_types_rebuild();
+}
+
+/**
  * Implements hook_help().
  */
 function node_help($path, $arg) {
@@ -119,9 +125,8 @@ function node_help($path, $arg) {
       return '<p>' . t('Individual content types can have different fields, behaviors, and permissions assigned to them.') . '</p>';
 
     case 'admin/structure/types/manage/%/display':
-      $type =  entity_load('node_type', $arg[4]);
       return '<p>' . t('Content items can be displayed using different view modes: Teaser, Full content, Print, RSS, etc. <em>Teaser</em> is a short format that is typically used in lists of multiple content items. <em>Full content</em> is typically used when the content is displayed on its own page.') . '</p>' .
-        '<p>' . t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', array('%type' => $type->label())) . '</p>';
+        '<p>' . t('Here, you can define which fields are shown and hidden when %type content is displayed in each view mode, and define how the fields are displayed in each view mode.', array('%type' => node_type_get_label($arg[4]))) . '</p>';
 
     case 'node/%/revisions':
       return '<p>' . t('Revisions allow you to track differences between multiple versions of your content, and revert back to older versions.') . '</p>';
@@ -158,6 +163,10 @@ function node_theme() {
       'variables' => array('node' => NULL),
       'file' => 'node.pages.inc',
     ),
+    'node_admin_overview' => array(
+      'variables' => array('name' => NULL, 'type' => NULL),
+      'file' => 'content_types.inc',
+    ),
     'node_recent_block' => array(
       'variables' => array('nodes' => NULL),
     ),
@@ -178,8 +187,9 @@ function node_entity_bundle_info() {
   $bundles = array();
   // Bundles must provide a human readable name so we can create help and error
   // messages.
-  foreach (node_type_get_names() as $id => $label) {
-    $bundles['node'][$id]['label'] = $label;
+  node_type_cache_reset();
+  foreach (node_type_get_names() as $type => $name) {
+    $bundles['node'][$type]['label'] = $name;
   }
   return $bundles;
 }
@@ -295,43 +305,63 @@ function node_mark($nid, $timestamp) {
  * Returns a list of all the available node types.
  *
  * This list can include types that are queued for addition or deletion.
+ * See _node_types_build() for details.
  *
- * @return array
- *   An array of node type entities, keyed by ID.
+ * @return
+ *   An array of node types, as objects, keyed by the type.
  *
+ * @see _node_types_build()
  * @see node_type_load()
  */
 function node_type_get_types() {
-  return entity_load_multiple('node_type');
+  return _node_types_build()->types;
+}
+
+/**
+ * Returns the node type base of the passed node or node type string.
+ *
+ * The base indicates which module implements this node type and is used to
+ * execute node-type-specific hooks. For types defined in the user interface
+ * and managed by node.module, the base is 'node_content'.
+ *
+ * @param string $type
+ *   A string that indicates the node type to return.
+ *
+ * @return string|false
+ *   The node type base or FALSE if the node type is not found.
+ */
+function node_type_get_base($type) {
+  $types = _node_types_build()->types;
+  return isset($types[$type]) && isset($types[$type]->base) ? $types[$type]->base : FALSE;
 }
 
 /**
  * Returns a list of available node type names.
  *
  * This list can include types that are queued for addition or deletion.
+ * See _node_types_build() for details.
  *
- * @return array
+ * @return
  *   An array of node type labels, keyed by the node type name.
+ *
+ * @see _node_types_build()
  */
 function node_type_get_names() {
-  $cid = 'node_type:names:' . language(Language::TYPE_INTERFACE)->langcode;
-  if ($cache = cache()->get($cid)) {
-    return $cache->data;
-  }
-  // Not using node_type_get_types() or entity_load_multiple() here, to allow
-  // this function being used in hook_entity_info() implementations.
-  // @todo Consider to convert this into a generic config entity helper.
-  $config_names = config_get_storage_names_with_prefix('node.type.');
-  $names = array();
-  foreach ($config_names as $config_name) {
-    $config = config($config_name);
-    $names[$config->get('type')] = $config->get('name');
-  }
-  cache()->set($cid, $names, CacheBackendInterface::CACHE_PERMANENT, array(
-    'node_type' => array_keys($names),
-    'node_types' => TRUE,
-  ));
-  return $names;
+  return _node_types_build()->names;
+}
+
+/**
+ * Returns the node type label for the passed node type name.
+ *
+ * @param string $name
+ *   The machine name of a node type.
+ *
+ * @return string|false
+ *   The node type label or FALSE if the node type is not found.
+ */
+function node_type_get_label($name) {
+  $types = _node_types_build()->names;
+  return isset($types[$name]) ? $types[$name] : FALSE;
 }
 
 /**
@@ -342,45 +372,152 @@ function node_type_get_names() {
  *
  * @return string|false
  *   The node type label or FALSE if the node type is not found.
- *
- * @todo Add this as generic helper method for config entities representing
- *   entity bundles.
  */
 function node_get_type_label(EntityInterface $node) {
-  $type = entity_load('node_type', $node->bundle());
-  return $type ? $type->label() : FALSE;
+  $types = _node_types_build()->names;
+  return isset($types[$node->type]) ? $types[$node->type] : FALSE;
+}
+
+/**
+ * Title callback: Returns the sanitized node type name.
+ *
+ * @param $node_type
+ *   The node type object.
+ *
+ * @return
+ *   The node type name that is safe for printing.
+ */
+function node_type_get_clean_name($node_type) {
+  return check_plain($node_type->name);
 }
 
 /**
  * Description callback: Returns the node type description.
  *
- * @param \Drupal\node\NodeTypeInterface $node_type
+ * @param $node_type
  *   The node type object.
  *
- * @return string
+ * @return
  *   The node type description.
  */
-function node_type_get_description(NodeTypeInterface $node_type) {
+function node_type_get_description($node_type) {
   return $node_type->description;
 }
 
 /**
+ * Updates the database cache of node types.
+ *
+ * All new module-defined node types are saved to the database via a call to
+ * node_type_save(), and obsolete ones are deleted via a call to
+ * node_type_delete(). See _node_types_build() for an explanation of the new
+ * and obsolete types.
+ *
+ * @see _node_types_build()
+ */
+function node_types_rebuild() {
+  _node_types_build(TRUE);
+}
+
+/**
  * Menu argument loader: Loads a node type by string.
  *
  * @param $name
  *   The machine name of a node type to load.
  *
- * @return \Drupal\node\NodeTypeInterface
+ * @return
  *   A node type object or FALSE if $name does not exist.
  */
 function node_type_load($name) {
-  return entity_load('node_type', $name);
+  $types = _node_types_build()->types;
+  return isset($types[$name]) ? $types[$name] : FALSE;
+}
+
+/**
+ * Saves a node type to the database.
+ *
+ * @param object $info
+ *   The node type to save; an object with the following properties:
+ *   - type: A string giving the machine name of the node type.
+ *   - name: A string giving the human-readable name of the node type.
+ *   - base: A string that indicates the base string for hook functions. For
+ *     example, 'node_content' is the value used by the UI when creating a new
+ *     node type.
+ *   - description: A string that describes the node type.
+ *   - help: A string giving the help information shown to the user when
+ *     creating a node of this type.
+ *   - custom: TRUE or FALSE indicating whether this type is defined by a module
+ *     (FALSE) or by a user (TRUE) via Add Content Type.
+ *   - modified: TRUE or FALSE indicating whether this type has been modified by
+ *     an administrator. Currently not used in any way.
+ *   - locked: TRUE or FALSE indicating whether the administrator can change the
+ *     machine name of this type.
+ *   - disabled: TRUE or FALSE indicating whether this type has been disabled.
+ *   - has_title: TRUE or FALSE indicating whether this type uses the node title
+ *     field.
+ *   - title_label: A string containing the label for the title.
+ *   - module: A string giving the module defining this type of node.
+ *   - orig_type: A string giving the original machine-readable name of this
+ *     node type. This may be different from the current type name if the locked
+ *     field is 0.
+ *
+ * @return int
+ *   A status flag indicating the outcome of the operation, either SAVED_NEW or
+ *   SAVED_UPDATED.
+ */
+function node_type_save($info) {
+  $existing_type = !empty($info->old_type) ? $info->old_type : $info->type;
+  $is_existing = (bool) db_query_range('SELECT 1 FROM {node_type} WHERE type = :type', 0, 1, array(':type' => $existing_type))->fetchField();
+  $type = node_type_set_defaults($info);
+
+  $fields = array(
+    'type' => (string) $type->type,
+    'name' => (string) $type->name,
+    'base' => (string) $type->base,
+    'has_title' => (int) $type->has_title,
+    'title_label' => (string) $type->title_label,
+    'description' => (string) $type->description,
+    'help' => (string) $type->help,
+    'custom' => (int) $type->custom,
+    'modified' => (int) $type->modified,
+    'locked' => (int) $type->locked,
+    'disabled' => (int) $type->disabled,
+    'module' => $type->module,
+  );
+
+  if ($is_existing) {
+    db_update('node_type')
+      ->fields($fields)
+      ->condition('type', $existing_type)
+      ->execute();
+
+    if (!empty($type->old_type) && $type->old_type != $type->type) {
+      entity_invoke_bundle_hook('rename', 'node', $type->old_type, $type->type);
+    }
+    module_invoke_all('node_type_update', $type);
+    $status = SAVED_UPDATED;
+  }
+  else {
+    $fields['orig_type'] = (string) $type->orig_type;
+    db_insert('node_type')
+      ->fields($fields)
+      ->execute();
+
+    entity_invoke_bundle_hook('create', 'node', $type->type);
+
+    module_invoke_all('node_type_insert', $type);
+    $status = SAVED_NEW;
+  }
+
+  // Clear the node type cache.
+  node_type_cache_reset();
+
+  return $status;
 }
 
 /**
  * Adds the default body field to a node type.
  *
- * @param \Drupal\node\NodeTypeInterface $type
+ * @param $type
  *   A node type object.
  * @param $label
  *   (optional) The label for the body instance.
@@ -388,10 +525,10 @@ function node_type_load($name) {
  * @return
  *   Body field instance.
  */
-function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
+function node_add_body_field($type, $label = 'Body') {
    // Add or remove the body field, as needed.
   $field = field_info_field('body');
-  $instance = field_info_instance('node', 'body', $type->id());
+  $instance = field_info_instance('node', 'body', $type->type);
   if (empty($field)) {
     $field = entity_create('field_entity', array(
       'field_name' => 'body',
@@ -404,7 +541,7 @@ function node_add_body_field(NodeTypeInterface $type, $label = 'Body') {
     $instance = entity_create('field_instance', array(
       'field_name' => 'body',
       'entity_type' => 'node',
-      'bundle' => $type->id(),
+      'bundle' => $type->type,
       'label' => $label,
       'settings' => array('display_summary' => TRUE),
     ));
@@ -478,24 +615,198 @@ function node_field_extra_fields() {
 }
 
 /**
+ * Deletes a node type from the database.
+ *
+ * @param $name
+ *   The machine name of the node type to delete.
+ */
+function node_type_delete($name) {
+  $type = node_type_load($name);
+  db_delete('node_type')
+    ->condition('type', $name)
+    ->execute();
+  entity_invoke_bundle_hook('delete', 'node', $name);
+  module_invoke_all('node_type_delete', $type);
+
+  // Clear the node type cache.
+  node_type_cache_reset();
+}
+
+/**
  * Updates all nodes of one type to be of another type.
  *
- * @param string $old_id
+ * @param $old_type
  *   The current node type of the nodes.
- * @param string $new_id
+ * @param $type
  *   The new node type of the nodes.
  *
  * @return
  *   The number of nodes whose node type field was modified.
  */
-function node_type_update_nodes($old_id, $new_id) {
+function node_type_update_nodes($old_type, $type) {
   return db_update('node')
-    ->fields(array('type' => $new_id))
-    ->condition('type', $old_id)
+    ->fields(array('type' => $type))
+    ->condition('type', $old_type)
     ->execute();
 }
 
 /**
+ * Builds and returns the list of available node types.
+ *
+ * The list of types is built by invoking hook_node_info() on all modules and
+ * comparing this information with the node types in the {node_type} table.
+ * These two information sources are not synchronized during module installation
+ * until node_types_rebuild() is called.
+ *
+ * @param $rebuild
+ *  (optional) TRUE to rebuild node types. Equivalent to calling
+ *  node_types_rebuild(). Defaults to FALSE.
+ *
+ * @return
+ *   An object with two properties:
+ *   - names: Associative array of the names of node types, keyed by the type.
+ *   - types: Associative array of node type objects, keyed by the type.
+ *   Both of these arrays will include new types that have been defined by
+ *   hook_node_info() implementations but not yet saved in the {node_type}
+ *   table. These are indicated in the type object by $type->is_new being set
+ *   to the value 1. These arrays will also include obsolete types: types that
+ *   were previously defined by modules that have now been disabled, or for
+ *   whatever reason are no longer being defined in hook_node_info()
+ *   implementations, but are still in the database. These are indicated in the
+ *   type object by $type->disabled being set to TRUE.
+ */
+function _node_types_build($rebuild = FALSE) {
+  $cid = 'node_types:' . language(Language::TYPE_INTERFACE)->langcode;
+
+  if (!$rebuild) {
+    $_node_types = &drupal_static(__FUNCTION__);
+    if (isset($_node_types)) {
+      return $_node_types;
+    }
+    if ($cache = cache()->get($cid)) {
+      $_node_types = $cache->data;
+      return $_node_types;
+    }
+  }
+
+  $_node_types = (object) array('types' => array(), 'names' => array());
+
+  foreach (module_implements('node_info') as $module) {
+    $info_array = module_invoke($module, 'node_info');
+    foreach ($info_array as $type => $info) {
+      $info['type'] = $type;
+      $_node_types->types[$type] = node_type_set_defaults($info);
+      $_node_types->types[$type]->module = $module;
+      $_node_types->names[$type] = $info['name'];
+    }
+  }
+  $query = db_select('node_type', 'nt')
+    ->addTag('node_type_access')
+    ->fields('nt')
+    ->orderBy('nt.type', 'ASC');
+  if (!$rebuild) {
+    $query->condition('disabled', 0);
+  }
+  foreach ($query->execute() as $type_object) {
+    $type_db = $type_object->type;
+    // Original disabled value.
+    $disabled = $type_object->disabled;
+    // Check for node types from disabled modules and mark their types for removal.
+    // Types defined by the node module in the database (rather than by a separate
+    // module using hook_node_info) have a base value of 'node_content'. The isset()
+    // check prevents errors on old (pre-Drupal 7) databases.
+    if (isset($type_object->base) && $type_object->base != 'node_content' && empty($_node_types->types[$type_db])) {
+      $type_object->disabled = TRUE;
+    }
+    if (isset($_node_types->types[$type_db])) {
+      $type_object->disabled = FALSE;
+    }
+    if (!isset($_node_types->types[$type_db]) || $type_object->modified) {
+      $_node_types->types[$type_db] = $type_object;
+      $_node_types->names[$type_db] = $type_object->name;
+
+      if ($type_db != $type_object->orig_type) {
+        unset($_node_types->types[$type_object->orig_type]);
+        unset($_node_types->names[$type_object->orig_type]);
+      }
+    }
+    $_node_types->types[$type_db]->disabled = $type_object->disabled;
+    $_node_types->types[$type_db]->disabled_changed = $disabled != $type_object->disabled;
+  }
+
+  if ($rebuild) {
+    foreach ($_node_types->types as $type => $type_object) {
+      if (!empty($type_object->is_new) || !empty($type_object->disabled_changed)) {
+        node_type_save($type_object);
+      }
+    }
+  }
+
+  asort($_node_types->names);
+
+  cache()->set($cid, $_node_types, CacheBackendInterface::CACHE_PERMANENT, array('node_types' => TRUE));
+
+  return $_node_types;
+}
+
+/**
+ * Clears the node type cache.
+ */
+function node_type_cache_reset() {
+  cache()->deleteTags(array('node_types' => TRUE));
+  drupal_static_reset('_node_types_build');
+}
+
+/**
+ * Sets the default values for a node type.
+ *
+ * The defaults are appropriate for a type defined through hook_node_info(),
+ * since 'custom' is TRUE for types defined in the user interface, and FALSE
+ * for types defined by modules. (The 'custom' flag prevents types from being
+ * deleted through the user interface.) Also, the default for 'locked' is TRUE,
+ * which prevents users from changing the machine name of the type.
+ *
+ * @param $info
+ *   (optional) An object or array containing values to override the defaults.
+ *   See hook_node_info() for details on what the array elements mean. Defaults
+ *   to an empty array.
+ *
+ * @return
+ *   A node type object, with missing values in $info set to their defaults.
+ *
+ * @see hook_node_info()
+ */
+function node_type_set_defaults($info = array()) {
+  $info = (array) $info;
+  $new_type = $info + array(
+    'type' => '',
+    'name' => '',
+    'base' => '',
+    'description' => '',
+    'help' => '',
+    'custom' => 0,
+    'modified' => 0,
+    'locked' => 1,
+    'disabled' => 0,
+    'is_new' => 1,
+    'has_title' => 1,
+    'title_label' => 'Title',
+  );
+  $new_type = (object) $new_type;
+
+  // If the type has no title, set an empty label.
+  if (!$new_type->has_title) {
+    $new_type->title_label = '';
+  }
+  if (empty($new_type->module)) {
+    $new_type->module = $new_type->base == 'node_content' ? 'node' : '';
+  }
+  $new_type->orig_type = isset($info['type']) ? $info['type'] : '';
+
+  return $new_type;
+}
+
+/**
  * Implements hook_rdf_mapping().
  */
 function node_rdf_mapping() {
@@ -755,9 +1066,7 @@ function template_preprocess_node(&$variables) {
   field_attach_preprocess($node, $variables['content'], $variables);
 
   // Display post information only on certain node types.
-  // Avoid loading the entire node type config entity here.
-  $submitted = Drupal::config('node.type.' . $node->type)->get('settings.node.submitted') ?: TRUE;
-  if ($submitted) {
+  if (variable_get('node_submitted_' . $node->type, TRUE)) {
     $variables['display_submitted'] = TRUE;
     $variables['submitted'] = t('Submitted by !username on !datetime', array('!username' => $variables['name'], '!datetime' => $variables['date']));
     if (theme_get_setting('features.node_user_picture')) {
@@ -1272,7 +1581,9 @@ function node_menu() {
   $items['admin/structure/types'] = array(
     'title' => 'Content types',
     'description' => 'Manage content types, including default status, front page promotion, comment settings, etc.',
-    'route_name' => 'node_overview_types',
+    'page callback' => 'node_overview_types',
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
   );
   $items['admin/structure/types/list'] = array(
     'title' => 'List',
@@ -1280,14 +1591,20 @@ function node_menu() {
   );
   $items['admin/structure/types/add'] = array(
     'title' => 'Add content type',
-    'route_name' => 'node_type_add',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_type_form'),
+    'access arguments' => array('administer content types'),
     'type' => MENU_LOCAL_ACTION,
+    'file' => 'content_types.inc',
   );
   $items['admin/structure/types/manage/%node_type'] = array(
     'title' => 'Edit content type',
-    'title callback' => 'entity_page_label',
+    'title callback' => 'node_type_page_title',
     'title arguments' => array(4),
-    'route_name' => 'node_type_edit',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('node_type_form', 4),
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
   );
   $items['admin/structure/types/manage/%node_type/edit'] = array(
     'title' => 'Edit',
@@ -1295,7 +1612,9 @@ function node_menu() {
   );
   $items['admin/structure/types/manage/%node_type/delete'] = array(
     'title' => 'Delete',
-    'route_name' => 'node_type_delete_confirm',
+    'page arguments' => array('node_type_delete_confirm', 4),
+    'access arguments' => array('administer content types'),
+    'file' => 'content_types.inc',
   );
   $items['node/add'] = array(
     'title' => 'Add content',
@@ -1304,7 +1623,7 @@ function node_menu() {
     'file' => 'node.pages.inc',
   );
   $items['node/add/%node_type'] = array(
-    'title callback' => 'entity_page_label',
+    'title callback' => 'node_type_get_clean_name',
     'title arguments' => array(2),
     'page callback' => 'node_add',
     'page arguments' => array(2),
@@ -1398,6 +1717,21 @@ function node_menu_local_tasks(&$data, $router_item, $root_path) {
 }
 
 /**
+ * Title callback: Provides the title for a node type edit form.
+ *
+ * @param $type
+ *   The node type object.
+ *
+ * @return string
+ *   An unsanitized string that is the title of the node type edit form.
+ *
+ * @see node_menu()
+ */
+function node_type_page_title($type) {
+  return $type->name;
+}
+
+/**
  * Title callback: Displays the node's title.
  *
  * @param \Drupal\Core\Entity\EntityInterface $node
@@ -1604,27 +1938,6 @@ function node_form_block_form_alter(&$form, &$form_state) {
 }
 
 /**
- * Implements hook_modules_uninstalled().
- */
-function node_modules_uninstalled($modules) {
-  // Remove module-specific settings from all node types.
-  $config_names = config_get_storage_names_with_prefix('node.type.');
-  foreach ($config_names as $config_name) {
-    $config = config($config_name);
-    $changed = FALSE;
-    foreach ($modules as $module) {
-      if ($config->get('settings.' . $module)) {
-        $config->clear('settings.' . $module);
-        $changed = TRUE;
-      }
-    }
-    if ($changed) {
-      $config->save();
-    }
-  }
-}
-
-/**
  * Implements hook_block_access().
  *
  * Checks the content type specific visibility settings and removes the block
@@ -2150,10 +2463,8 @@ function node_form_system_themes_admin_form_submit($form, &$form_state) {
  */
 function node_access($op, $node, $account = NULL, $langcode = NULL) {
   if (!$node instanceof EntityInterface) {
-    $node = entity_create('node', array('type' => $node));
-  }
-  elseif ($node instanceof NodeTypeInterface) {
-    $node = entity_create('node', array('type' => $node->id()));
+    $type = is_object($node) ? $node->type : $node;
+    $node = entity_create('node', array('type' => $type));
   }
 
   // If no language code was provided, default to the node's langcode.
@@ -2269,8 +2580,7 @@ function node_list_permissions($type) {
 function node_permissions_get_configured_types() {
   $configured_types = array();
   foreach (node_type_get_types() as $name => $type) {
-    $node_settings = $type->getModuleSettings('node');
-    if (!isset($node_settings['permissions']) || !empty($node_settings['permissions'])) {
+    if (variable_get('node_permissions_' . $name, 1)) {
       $configured_types[$name] = $type;
     }
   }
diff --git a/core/modules/node/node.routing.yml b/core/modules/node/node.routing.yml
index 9204a2b..ce897f5 100644
--- a/core/modules/node/node.routing.yml
+++ b/core/modules/node/node.routing.yml
@@ -4,46 +4,9 @@ node_multiple_delete_confirm:
     _form: '\Drupal\node\Form\DeleteMultiple'
   requirements:
     _permission: 'administer nodes'
-
 node_page_edit:
   pattern: '/node/{node}/edit'
   defaults:
     _entity_form: 'node.edit'
   requirements:
     _entity_access: 'node.update'
-
-node_overview_types:
-  pattern: '/admin/structure/types'
-  defaults:
-    _content: '\Drupal\Core\Entity\Controller\EntityListController::listing'
-    entity_type: 'node_type'
-  requirements:
-    _permission: 'administer content types'
-
-node_type_add:
-  pattern: '/admin/structure/types/add'
-  defaults:
-    _entity_form: 'node_type.add'
-  requirements:
-    _permission: 'administer content types'
-
-node_type_edit:
-  pattern: '/admin/structure/types/manage/{node_type}'
-  defaults:
-    _entity_form: 'node_type.edit'
-  requirements:
-    _permission: 'administer content types'
-
-node_type_edit_default:
-  pattern: '/admin/structure/types/manage/{node_type}/edit'
-  defaults:
-    _entity_form: 'node_type.edit'
-  requirements:
-    _permission: 'administer content types'
-
-node_type_delete_confirm:
-  pattern: '/admin/structure/types/manage/{node_type}/delete'
-  defaults:
-    _entity_form: 'node_type.delete'
-  requirements:
-    _entity_access: 'node_type.delete'
diff --git a/core/modules/node/tests/modules/node_test_config/config/node.type.default.yml b/core/modules/node/tests/modules/node_test_config/config/node.type.default.yml
deleted file mode 100644
index a93a9c6..0000000
--- a/core/modules/node/tests/modules/node_test_config/config/node.type.default.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-type: default
-uuid: ca226632-3186-42a2-8440-a526f20840af
-name: Default
-description: 'Default description.'
-help: ''
-has_title: '1'
-title_label: Title
-settings:
-  node:
-    preview: '1'
-    options:
-      status: status
-      promote: promote
-      sticky: '0'
-      revision: '0'
-    submitted: '1'
-status: '1'
-langcode: en
diff --git a/core/modules/node/tests/modules/node_test_config/node_test_config.info.yml b/core/modules/node/tests/modules/node_test_config/node_test_config.info.yml
deleted file mode 100644
index 948b4a5..0000000
--- a/core/modules/node/tests/modules/node_test_config/node_test_config.info.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-name: 'Node configuration tests'
-type: module
-description: 'Support module for node configuration tests.'
-core: 8.x
-package: Testing
-version: VERSION
-hidden: TRUE
diff --git a/core/modules/node/tests/modules/node_test_config/node_test_config.module b/core/modules/node/tests/modules/node_test_config/node_test_config.module
deleted file mode 100644
index 00522b5..0000000
--- a/core/modules/node/tests/modules/node_test_config/node_test_config.module
+++ /dev/null
@@ -1,6 +0,0 @@
-<?php
-
-/**
- * @file
- * Helper module for node configuration tests.
- */
diff --git a/core/modules/node/tests/modules/node_test_config/staging/node.type.import.yml b/core/modules/node/tests/modules/node_test_config/staging/node.type.import.yml
deleted file mode 100644
index e5ce0ba..0000000
--- a/core/modules/node/tests/modules/node_test_config/staging/node.type.import.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-type: import
-uuid: 1a720d40-7bcd-41e3-ae4d-08d1cad4ac2a
-name: Import
-description: 'Import description.'
-help: ''
-has_title: '1'
-title_label: Title
-settings:
-  node:
-    preview: '1'
-    options:
-      status: status
-      promote: promote
-      sticky: '0'
-      revision: '0'
-    submitted: '1'
-status: '1'
-langcode: en
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 79b2854..180ea97 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -586,8 +586,7 @@ function overlay_overlay_child_initialize() {
   // actually did change, and, if so, trigger an immediate Ajax refresh
   // of the parent window.
   $token = Drupal::request()->query->get('token');
-  $post = Drupal::request()->request->count();
-  if (!empty($post) || isset($token)) {
+  if (!empty($_POST) || isset($token)) {
     foreach (overlay_supplemental_regions() as $region) {
       overlay_store_rendered_content($region, overlay_render_region($region));
     }
diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingAccessController.php b/core/modules/picture/lib/Drupal/picture/PictureMappingAccessController.php
deleted file mode 100644
index 5ee0ade..0000000
--- a/core/modules/picture/lib/Drupal/picture/PictureMappingAccessController.php
+++ /dev/null
@@ -1,31 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\picture\PictureMappingAccessController.
- */
-
-namespace Drupal\picture;
-
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines the access controller for the picture mapping entity type.
- */
-class PictureMappingAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
-    if ($operation === 'view') {
-      return TRUE;
-    }
-    elseif (in_array($operation, array('create', 'update', 'delete'))) {
-      return user_access('administer pictures', $account);
-    }
-  }
-
-}
diff --git a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php
index 0b63462..343dbd3 100644
--- a/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php
+++ b/core/modules/picture/lib/Drupal/picture/PictureMappingListController.php
@@ -32,7 +32,7 @@ public function hookMenu() {
   }
 
   /**
-   * {@inheritdoc}
+   * Overrides Drupal\config\ConfigEntityListController::getOperations();
    */
   public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
diff --git a/core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php b/core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php
index e10f86f..169292f 100644
--- a/core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php
+++ b/core/modules/picture/lib/Drupal/picture/Plugin/Core/Entity/PictureMapping.php
@@ -21,7 +21,6 @@
  *   module = "picture",
  *   controllers = {
  *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
- *     "access" = "Drupal\picture\PictureMappingAccessController",
  *     "list" = "Drupal\picture\PictureMappingListController",
  *     "form" = {
  *       "edit" = "Drupal\picture\PictureMappingFormController",
diff --git a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php
index b79ad21..927097d 100644
--- a/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php
+++ b/core/modules/picture/lib/Drupal/picture/Tests/PictureFieldDisplayTest.php
@@ -123,7 +123,7 @@ public function _testPictureFieldFormatters($scheme) {
     $node = node_load($nid, TRUE);
 
     // Test that the default formatter is being used.
-    $image_uri = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'])->getFileUri();
+    $image_uri = file_load($node->{$field_name}[Language::LANGCODE_NOT_SPECIFIED][0]['fid'])->getFileUri();
     $image_info = array(
       'uri' => $image_uri,
       'width' => 40,
diff --git a/core/modules/rdf/lib/Drupal/rdf/SchemaOrgDataConverter.php b/core/modules/rdf/lib/Drupal/rdf/SchemaOrgDataConverter.php
new file mode 100644
index 0000000..c3e0d69
--- /dev/null
+++ b/core/modules/rdf/lib/Drupal/rdf/SchemaOrgDataConverter.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\rdf\SchemaOrgDataConverter.
+ */
+
+namespace Drupal\rdf;
+
+
+class SchemaOrgDataConverter {
+
+  /**
+   * Converts an interaction count to a string with the interaction type.
+   *
+   * Schema.org defines a number of different interaction types.
+   *
+   * @param int $count
+   *   The interaction count.
+   *
+   * @return string
+   *   The formatted string.
+   *
+   * @see http://schema.org/UserInteraction
+   * @todo Support other interaction types, see https://drupal.org/node/2020001
+   */
+  static function interactionCount($count) {
+    return "UserComment:$count";
+  }
+}
\ No newline at end of file
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
index 8c6319a..6c705e3 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php
@@ -69,7 +69,7 @@ public function setUp() {
     $mapping = rdf_get_mapping('comment', 'comment_node_article');
     $mapping->setBundleMapping(array('types' => array('sioc:Post', 'sioct:Comment')))->save();
     $field_mappings = array(
-      'title' => array(
+      'subject' => array(
         'properties' => array('dc:title'),
       ),
       'created' => array(
@@ -251,7 +251,7 @@ function _testBasicCommentRdfaMarkup($graph, $comment, $account = array()) {
       'value' => $comment->subject->value,
       'lang' => 'en',
     );
-    $this->assertTrue($graph->hasProperty($comment_uri, 'http://purl.org/dc/terms/title', $expected_value), 'Comment title found in RDF output (dc:title).');
+    $this->assertTrue($graph->hasProperty($comment_uri, 'http://purl.org/dc/terms/title', $expected_value), 'Comment subject found in RDF output (dc:title).');
 
     // Comment date.
     $expected_value = array(
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
index 11176dc..91845ca 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/FileFieldAttributesTest.php
@@ -73,7 +73,7 @@ public function setUp() {
     $nid = $this->uploadNodeFile($test_file, $this->fieldName, $type_name);
 
     $this->node = node_load($nid, TRUE);
-    $this->file = file_load($this->node->{$this->fieldName}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $this->file = file_load($this->node->{$this->fieldName}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
 
   }
 
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php
index 338ddfb..72bf85a 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/ImageFieldAttributesTest.php
@@ -73,7 +73,7 @@ public function setUp() {
     // Save a node with the image.
     $nid = $this->uploadNodeImage($image, $this->fieldName, 'article');
     $this->node = node_load($nid);
-    $this->file = file_load($this->node->{$this->fieldName}[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $this->file = file_load($this->node->{$this->fieldName}[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
   }
 
   /**
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaAttributesTest.php
index 314a4eb..e2de46a 100644
--- a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaAttributesTest.php
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaAttributesTest.php
@@ -84,6 +84,28 @@ function testDatatypeCallback() {
     $this->_testAttributes($expected_attributes, $mapping, $date);
   }
 
+
+  /**
+   * Test attribute creation for mappings which use data converters.
+   */
+  function testDatatypeCallbackWithConverter() {
+    $properties = array('schema:interactionCount');
+
+    $data = "23";
+    $content = "UserComment:23";
+
+    $mapping = array(
+      'properties' => $properties,
+      'datatype_callback' => 'Drupal\rdf\SchemaOrgDataConverter::interactionCount',
+    );
+    $expected_attributes = array(
+      'property' => $properties,
+      'content' => $content,
+    );
+
+    $this->_testAttributes($expected_attributes, $mapping, $data);
+  }
+
   /**
    * Test attribute creation for mappings which use 'rel'.
    */
diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/StandardProfileTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/StandardProfileTest.php
new file mode 100644
index 0000000..167d081
--- /dev/null
+++ b/core/modules/rdf/lib/Drupal/rdf/Tests/StandardProfileTest.php
@@ -0,0 +1,529 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\rdf\Tests\StandardProfileTest
+ */
+
+namespace Drupal\rdf\Tests;
+
+use Drupal\simpletest\WebTestBase;
+
+/**
+ * Tests that the standard profile mappings are set and exposed as expected.
+ */
+class StandardProfileTest extends WebTestBase {
+
+  public $profile = 'standard';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Standard profile RDF',
+      'description' => 'Tests the RDF mappings and RDFa markup of the standard profile.',
+      'group' => 'RDF',
+    );
+  }
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->base_uri = url('<front>', array('absolute' => TRUE));
+
+    // Create two test users.
+    $this->adminUser = $this->drupalCreateUser(array(
+      'administer content types',
+      'administer comments',
+      'administer comment fields',
+      'skip comment approval',
+      'post comments',
+      'access comments',
+      'access content',
+    ));
+    $this->webUser = $this->drupalCreateUser(array(
+      'access comments',
+      'post comments',
+      'create article content',
+      'edit own comments',
+      'post comments',
+      'skip comment approval',
+      'access content',
+    ));
+
+    $this->drupalLogin($this->adminUser);
+
+    // Create term.
+    $this->term = entity_create('taxonomy_term', array(
+      'name' => $this->randomName(),
+      'description' => $this->randomName(),
+      'vid' => 'tags',
+    ));
+    $this->term->save();
+
+    // Create image.
+    file_unmanaged_copy(DRUPAL_ROOT . '/core/misc/druplicon.png', 'public://example.jpg');
+    $this->image = entity_create('file', array('uri' => 'public://example.jpg'));
+    $this->image->save();
+
+    // Create article.
+    $article_settings = array(
+      'type' => 'article',
+      'promote' => NODE_PROMOTED,
+      'field_image' => array(
+        array(
+          'fid' => $this->image->id(),
+        ),
+      ),
+      'field_tags' => array(
+        array(
+          'target_id' => $this->term->id(),
+        ),
+      ),
+    );
+    $this->article = $this->drupalCreateNode($article_settings);
+    // Create second article to test teaser list.
+    $this->drupalCreateNode(array('type' => 'article', 'promote' => NODE_PROMOTED,));
+
+    // Create article comment.
+    $this->articleComment = $this->saveComment($this->article->id(), $this->webUser->id(), NULL, 0, 'comment_node_article');
+
+    // Create page.
+    $this->page = $this->drupalCreateNode(array('type' => 'page'));
+
+    // Set URIs.
+    // Image.
+    $image_file = file_load($this->article->get('field_image')->offsetGet(0)->get('fid')->getValue());
+    $this->imageUri = image_style_url('large', $image_file->getFileUri());
+    // Term.
+    $term_uri_info = $this->term->uri();
+    $this->termUri = url($term_uri_info['path'], array('absolute' => TRUE));
+    // Article.
+    $article_uri_info = $this->article->uri();
+    $this->articleUri = url($article_uri_info['path'], array('absolute' => TRUE));
+    // Page.
+    $page_uri_info = $this->page->uri();
+    $this->pageUri = url($page_uri_info['path'], array('absolute' => TRUE));
+    // Author.
+    $this->authorUri = url('user/' . $this->adminUser->uid, array('absolute' => TRUE));
+    // Comment.
+    $article_comment_uri_info = $this->articleComment->uri();
+    $this->articleCommentUri = url($article_comment_uri_info['path'], array('absolute' => TRUE));
+    // Commenter.
+    $commenter_uri_info = $this->webUser->uri();
+    $this->commenterUri = url($commenter_uri_info['path'], array('absolute' => TRUE));
+
+    $this->drupalLogout();
+  }
+
+  /**
+   * Test that the mappings are set and exposed.
+   *
+   * Because tests using standard profile take a very long time to run, and
+   * because there is no manipulation of config or data within the test, simply
+   * run all the tests from within this function.
+   */
+  public function testMappingsAndOutput() {
+    // Test mappings.
+    $this->_testArticleMapping();
+    $this->_testPageMapping();
+
+    // Test displays.
+    $this->_testFrontPageRDFa();
+    $this->_testArticleRDFa();
+    $this->_testPageRDFa();
+  }
+
+  /**
+   * Test that the standard mapping for page has been saved.
+   */
+  protected function _testArticleMapping() {
+    $article_mapping = rdf_get_mapping('node', 'article');
+
+    // Bundle.
+    $bundle_mapping = $article_mapping->getBundleMapping();
+    $this->assertEqual(array('schema:Article'), $bundle_mapping['types'], "Article is mapped to schema:Article.");
+
+    // Title.
+    $title_mapping = $article_mapping->getFieldMapping('title');
+    $this->assertEqual(array('schema:name'), $title_mapping['properties'], "Article title is mapped to schema:name.");
+
+    // Created date.
+    $created_mapping = $article_mapping->getFieldMapping('created');
+    $this->assertEqual(array('schema:dateCreated'), $created_mapping['properties'], "Article created date is mapped to schema:dateCreated.");
+    $this->assertEqual('date_iso8601', $created_mapping['datatype_callback'], "Article created date has datatype callback 'date_iso8601'.");
+
+    // Changed date.
+    $changed_mapping = $article_mapping->getFieldMapping('changed');
+    $this->assertEqual(array('schema:dateModified'), $changed_mapping['properties'], "Article changed date is mapped to schema:dateModified.");
+    $this->assertEqual('date_iso8601', $changed_mapping['datatype_callback'], "Article changed date has datatype callback 'date_iso8601'.");
+
+    // Body.
+    $body_mapping = $article_mapping->getFieldMapping('body');
+    $this->assertEqual(array('schema:text'), $body_mapping['properties'], "Article body is mapped to schema:text.");
+
+    // Uid.
+    $uid_mapping = $article_mapping->getFieldMapping('uid');
+    $this->assertEqual(array('schema:author'), $uid_mapping['properties'], "Article uid is mapped to schema:author.");
+    $this->assertEqual('rel', $uid_mapping['mapping_type'], "Article uid uses 'rel' mapping_type.");
+
+    // Comment count.
+    $comment_count_mapping = $article_mapping->getFieldMapping('comment_count');
+    $this->assertEqual(array('schema:interactionCount'), $comment_count_mapping['properties'], "Article comment count is mapped to schema:interactionCount.");
+    $this->assertEqual('Drupal\rdf\SchemaOrgDataConverter::interactionCount', $comment_count_mapping['datatype_callback'], "Article comment count uses correct datatype callback.");
+
+    // Image.
+    $image_mapping = $article_mapping->getFieldMapping('field_image');
+    $this->assertEqual(array('schema:image'), $image_mapping['properties'], "Article image is mapped to schema:image.");
+    $this->assertEqual('rel', $image_mapping['mapping_type'], "Article image uses 'rel' mapping_type.");
+
+    // Tags.
+    $tags_mapping = $article_mapping->getFieldMapping('field_tags');
+    $this->assertEqual(array('schema:about'), $tags_mapping['properties'], "Article tags are mapped to schema:about.");
+    $this->assertEqual('rel', $tags_mapping['mapping_type'], "Article tags uses 'rel' mapping_type.");
+  }
+
+  /**
+   * Test that the standard mapping for page has been saved.
+   */
+  protected function _testPageMapping() {
+    $page_mapping = rdf_get_mapping('node', 'page');
+
+    // Bundle.
+    $bundle_mapping = $page_mapping->getBundleMapping();
+    $this->assertEqual(array('schema:WebPage'), $bundle_mapping['types'], "Page is mapped to schema:WebPage.");
+
+    // Title.
+    $title_mapping = $page_mapping->getFieldMapping('title');
+    $this->assertEqual(array('schema:name'), $title_mapping['properties'], "Page title is mapped to schema:name.");
+
+    // Created date.
+    $created_mapping = $page_mapping->getFieldMapping('created');
+    $this->assertEqual(array('schema:dateCreated'), $created_mapping['properties'], "Page created date is mapped to schema:dateCreated.");
+    $this->assertEqual('date_iso8601', $created_mapping['datatype_callback'], "Page created date has datatype callback 'date_iso8601'.");
+
+    // Changed date.
+    $changed_mapping = $page_mapping->getFieldMapping('changed');
+    $this->assertEqual(array('schema:dateModified'), $changed_mapping['properties'], "Page changed date is mapped to schema:dateModified.");
+    $this->assertEqual('date_iso8601', $changed_mapping['datatype_callback'], "Page changed date has datatype callback 'date_iso8601'.");
+
+    // Body.
+    $body_mapping = $page_mapping->getFieldMapping('body');
+    $this->assertEqual(array('schema:text'), $body_mapping['properties'], "Page body is mapped to schema:text.");
+
+    // Uid.
+    $uid_mapping = $page_mapping->getFieldMapping('uid');
+    $this->assertEqual(array('schema:author'), $uid_mapping['properties'], "Page uid is mapped to schema:author.");
+    $this->assertEqual('rel', $uid_mapping['mapping_type'], "Page uid uses 'rel' mapping_type.");
+
+    // Comment count.
+    $comment_count_mapping = $page_mapping->getFieldMapping('comment_count');
+    $this->assertEqual(array('schema:interactionCount'), $comment_count_mapping['properties'], "Page comment count is mapped to schema:interactionCount.");
+    $this->assertEqual('Drupal\rdf\SchemaOrgDataConverter::interactionCount', $comment_count_mapping['datatype_callback'], "Page comment count uses correct datatype callback.");
+  }
+
+  /**
+   * Test that data is exposed in the front page teasers.
+   */
+  protected function _testFrontPageRDFa() {
+    $path = 'node';
+
+    // Feed the HTML into the parser.
+    $parser = new \EasyRdf_Parser_Rdfa();
+    $graph = new \EasyRdf_Graph();
+    $parser->parse($graph, $this->drupalGet($path), 'rdfa', $this->base_uri);
+
+    // Ensure that both articles are listed.
+    $this->assertEqual(2, count($graph->allOfType('http://schema.org/Article')), 'Two articles found on front page.');
+
+    // Test interaction count.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => 'UserComment:1',
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->articleUri, 'http://schema.org/interactionCount', $expected_value), "Teaser comment count was found (schema:interactionCount).");
+
+    // Test the properties that are common between pages and articles and are
+    // displayed in full and teaser mode.
+    $this->_testCommonNodeProperties($graph, $this->article, "Teaser");
+    // Test properties that are displayed in both teaser and full mode.
+    $this->_testArticleProperties($graph, "Teaser");
+
+    // Title.
+    // @todo Once the title data is output consistently between full and teaser
+    // view modes, move this to _testCommonNodeProperties().
+    $title = $this->article->get('title')->offsetGet(0)->get('value')->getValue();
+    $expected_value = array(
+      'type' => 'literal',
+      // The teaser title parses with additional whitespace.
+      'value' => "
+        $title
+      ",
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->articleUri, 'http://schema.org/name', $expected_value), "Teaser title was found (schema:name).");
+
+    // @todo Once the image points to the original instead of the processed
+    // image, move this to testArticleProperties().
+    $image_file = file_load($this->article->get('field_image')->offsetGet(0)->get('fid')->getValue());
+    $image_uri = image_style_url('medium', $image_file->getFileUri());
+    $expected_value = array(
+      'type' => 'uri',
+      'value' => $image_uri,
+    );
+    $this->assertTrue($graph->hasProperty($this->articleUri, 'http://schema.org/image', $expected_value), "Teaser image was found (schema:image).");
+  }
+
+  /**
+   * Test that article data is exposed using RDFa.
+   *
+   * Two fields are not tested for output here. Changed date is not displayed
+   * on the page, so there is no test for output in node view. Comment count is
+   * displayed in teaser view, so it is tested in the front article tests.
+   */
+  protected function _testArticleRDFa() {
+    $uri_info = $this->article->uri();
+    $path = $uri_info['path'];
+
+    // Feed the HTML into the parser.
+    $parser = new \EasyRdf_Parser_Rdfa();
+    $graph = new \EasyRdf_Graph();
+    $parser->parse($graph, $this->drupalGet($path), 'rdfa', $this->base_uri);
+
+    // Type.
+    $this->assertEqual($graph->type($this->articleUri), 'schema:Article', 'Article type was found (schema:Article).');
+
+    // Test the properties that are common between pages and articles.
+    $this->_testCommonNodeProperties($graph, $this->article, "Article");
+    // Test properties that are displayed in both teaser and full mode.
+    $this->_testArticleProperties($graph, "Article");
+    // Test the comment properties displayed on articles.
+    $this->_testNodeCommentProperties($graph);
+
+    // Title.
+    // @todo Once the title data is output consistently between full and teaser
+    // view modes, move this to _testCommonNodeProperties().
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $this->article->get('title')->offsetGet(0)->get('value')->getValue(),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->articleUri, 'http://schema.org/name', $expected_value), "Article title was found (schema:name).");
+
+    // @todo Once the image points to the original instead of the processed
+    // image, move this to testArticleProperties().
+    $expected_value = array(
+      'type' => 'uri',
+      'value' => $this->imageUri,
+    );
+    $this->assertTrue($graph->hasProperty($this->articleUri, 'http://schema.org/image', $expected_value), "Article image was found (schema:image).");
+  }
+
+  /**
+   * Test that page data is exposed using RDFa.
+   *
+   * Two fields are not tested for output here. Changed date is not displayed
+   * on the page, so there is no test for output in node view. Comment count is
+   * displayed in teaser view, so it is tested in the front page tests.
+   */
+  protected function _testPageRDFa() {
+    // The standard profile hides the created date on pages. Revert display to
+    // true for testing.
+    variable_set('node_submitted_page', TRUE);
+
+    $path = 'node/' . $this->page->nid;
+    $this->pageUri = url($path, array('absolute' => TRUE));
+    $user_uri = url('user/' . $this->adminUser->uid, array('absolute' => TRUE));
+
+    // Feed the HTML into the parser.
+    $parser = new \EasyRdf_Parser_Rdfa();
+    $graph = new \EasyRdf_Graph();
+    $parser->parse($graph, $this->drupalGet($path), 'rdfa', $this->base_uri);
+
+    // Type.
+    $this->assertEqual($graph->type($this->pageUri), 'schema:WebPage', 'Page type was found (schema:WebPage).');
+
+    // Test the properties that are common between pages and articles.
+    $this->_testCommonNodeProperties($graph, $this->page, "Page");
+
+    // Title.
+    // @todo Once the title data is output consistently between full and teaser
+    // view modes, move this to _testCommonNodeProperties().
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $this->page->get('title')->offsetGet(0)->get('value')->getValue(),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->pageUri, 'http://schema.org/name', $expected_value), "Page title was found (schema:name).");
+  }
+
+  /**
+   * Test output for properties held in common between articles and pages.
+   *
+   * @param $graph
+   *   The EasyRDF graph object.
+   * @param $node
+   *   The node being displayed.
+   * @param $message_prefix
+   *   The word to use in the test assertion message.
+   */
+  function _testCommonNodeProperties($graph, $node, $message_prefix) {
+    // Article.
+    $uri_info = $node->uri();
+    $uri = url($uri_info['path'], array('absolute' => TRUE));
+
+    // Created date.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => date_iso8601($node->get('created')->offsetGet(0)->get('value')->getValue()),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($uri, 'http://schema.org/dateCreated', $expected_value), "$message_prefix created date was found (schema:dateCreated) in teaser.");
+
+    // Body.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $node->get('body')->offsetGet(0)->get('value')->getValue(),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($uri, 'http://schema.org/text', $expected_value), "$message_prefix body was found (schema:text) in teaser.");
+
+    // Author.
+    $expected_value = array(
+      'type' => 'uri',
+      'value' => $this->authorUri,
+    );
+    $this->assertTrue($graph->hasProperty($uri, 'http://schema.org/author', $expected_value), "$message_prefix author was found (schema:author) in teaser.");
+
+    // Author type.
+    $this->assertEqual($graph->type($this->authorUri), 'schema:Person', "$message_prefix author type was found (schema:Person).");
+
+    // Author name.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $this->adminUser->name,
+    );
+    $this->assertTrue($graph->hasProperty($this->authorUri, 'http://schema.org/name', $expected_value), "$message_prefix author name was found (schema:name).");
+  }
+
+  /**
+   * Test output for article properties displayed in both view modes.
+   *
+   * @param $graph
+   *   The EasyRDF graph object.
+   * @param $message_prefix
+   *   The word to use in the test assertion message.
+   */
+  function _testArticleProperties($graph, $message_prefix) {
+    // Tags.
+    $expected_value = array(
+      'type' => 'uri',
+      'value' => $this->termUri,
+    );
+    $this->assertTrue($graph->hasProperty($this->articleUri, 'http://schema.org/about', $expected_value), "$message_prefix tag was found (schema:about).");
+
+    // Tag type.
+    $this->assertEqual($graph->type($this->termUri), 'schema:Thing', 'Tag type was found (schema:Thing).');
+
+    // Tag name.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $this->term->get('name')->offsetGet(0)->get('value')->getValue(),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->termUri, 'http://schema.org/name', $expected_value), "$message_prefix name was found (schema:name).");
+  }
+
+  /**
+   * Test output for comment properties on nodes in full page view mode.
+   *
+   * @param $graph
+   *   The EasyRDF graph object.
+   */
+  function _testNodeCommentProperties($graph) {
+    // @todo Test relationship between comment and node once it is mapped.
+
+    // Comment type.
+    $this->assertEqual($graph->type($this->articleCommentUri), 'schema:Comment', 'Comment type was found (schema:Comment).');
+
+    // Comment title.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $this->articleComment->get('subject')->offsetGet(0)->get('value')->getValue(),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->articleCommentUri, 'http://schema.org/name', $expected_value), 'Article comment title was found (schema:name).');
+
+    // Comment created date.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => date_iso8601($this->articleComment->get('created')->offsetGet(0)->get('value')->getValue()),
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->articleCommentUri, 'http://schema.org/dateCreated', $expected_value), 'Article comment created date was found (schema:dateModified).');
+
+    // Comment body.
+    $text = $this->articleComment->get('comment_body')->offsetGet(0)->get('value')->getValue();
+    $expected_value = array(
+      'type' => 'literal',
+      // There is an extra carriage return in the when parsing comments as
+      // output by Bartik, so it must be added to the expected value.
+      'value' => "$text
+",
+      'lang' => 'en',
+    );
+    $this->assertTrue($graph->hasProperty($this->articleCommentUri, 'http://schema.org/text', $expected_value), 'Article comment body was found (schema:text).');
+
+    // Comment uid.
+    $expected_value = array(
+      'type' => 'uri',
+      'value' => $this->commenterUri,
+    );
+    $this->assertTrue($graph->hasProperty($this->articleCommentUri, 'http://schema.org/author', $expected_value), 'Article comment author was found (schema:author).');
+
+    // Comment author type.
+    $this->assertEqual($graph->type($this->commenterUri), 'schema:Person', 'Comment author type was found (schema:Person).');
+
+    // Comment author name.
+    $expected_value = array(
+      'type' => 'literal',
+      'value' => $this->webUser->get('name')->offsetGet(0)->get('value')->getValue(),
+    );
+    $this->assertTrue($graph->hasProperty($this->commenterUri, 'http://schema.org/name', $expected_value), 'Comment author name was found (schema:name).');
+  }
+
+  /**
+   * Creates a comment entity.
+   *
+   * @param $nid
+   *   Node id which will hold the comment.
+   * @param $uid
+   *   User id of the author of the comment. Can be NULL if $contact provided.
+   * @param $contact
+   *   Set to NULL for no contact info, TRUE to ignore success checking, and
+   *   array of values to set contact info.
+   * @param $pid
+   *   Comment id of the parent comment in a thread.
+   * @param $bundle
+   *   The bundle of the comment.
+   *
+   * @return \Drupal\comment\Plugin\Core\Entity\Comment
+   *   The saved comment.
+   */
+  function saveComment($nid, $uid, $contact = NULL, $pid = 0, $bundle) {
+    $values = array(
+      'nid' => $nid,
+      'uid' => $uid,
+      'pid' => $pid,
+      'node_type' => $bundle,
+      'subject' => $this->randomName(),
+      'comment_body' => $this->randomName(),
+      'status' => 1,
+    );
+    if ($contact) {
+      $values += $contact;
+    }
+
+    $comment = entity_create('comment', $values);
+    $comment->save();
+    return $comment;
+  }
+}
diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module
index 526ef66..bd97959 100644
--- a/core/modules/rdf/rdf.module
+++ b/core/modules/rdf/rdf.module
@@ -92,6 +92,7 @@ function rdf_rdf_namespaces() {
     'foaf'     => 'http://xmlns.com/foaf/0.1/',
     'og'       => 'http://ogp.me/ns#',
     'rdfs'     => 'http://www.w3.org/2000/01/rdf-schema#',
+    'schema'   => 'http://schema.org/',
     'sioc'     => 'http://rdfs.org/sioc/ns#',
     'sioct'    => 'http://rdfs.org/sioc/types#',
     'skos'     => 'http://www.w3.org/2004/02/skos/core#',
@@ -176,7 +177,7 @@ function rdf_rdfa_attributes($mapping, $data = NULL) {
         // Convert $data to a specific format as per the callback function.
         if (isset($data) && !empty($mapping['datatype_callback'])) {
           $callback = $mapping['datatype_callback'];
-          $attributes['content'] = $callback($data);
+          $attributes['content'] = call_user_func($callback, $data);
         }
         if (isset($mapping['datatype'])) {
           $attributes['datatype'] = $mapping['datatype'];
@@ -348,11 +349,7 @@ function rdf_preprocess_node(&$variables) {
   if (isset($variables['node']->comment_count) && !empty($comment_count_mapping['properties'])) {
     // Annotates the 'x comments' link in teaser view.
     if (isset($variables['content']['links']['comment']['#links']['comment-comments'])) {
-      $comment_count_attributes['property'] = $comment_count_mapping['properties'];
-      $comment_count_attributes['content'] = $variables['node']->comment_count;
-      if (isset($comment_count_mapping['datatype'])) {
-        $comment_count_attributes['datatype'] = $comment_count_mapping['datatype'];
-      }
+      $comment_count_attributes = rdf_rdfa_attributes($comment_count_mapping, $variables['node']->comment_count);
       // According to RDFa parsing rule number 4, a new subject URI is created
       // from the href attribute if no rel/rev attribute is present. To get the
       // original node URL from the about attribute of the parent container we
@@ -547,7 +544,7 @@ function rdf_preprocess_comment(&$variables) {
     $variables['rdf_template_variable_attributes']['author']['rel'] = $uid_mapping['properties'];
     $variables['rdf_template_variable_attributes']['submitted']['rel'] = $uid_mapping['properties'];
   }
-  $title_mapping = $mapping->getPreparedFieldMapping('title');
+  $title_mapping = $mapping->getPreparedFieldMapping('subject');
   if (!empty($title_mapping)) {
     // Adds RDFa markup to the subject of the comment. Because the RDFa markup
     // is added to an <h3> tag which might contain HTML code, we specify an
@@ -559,6 +556,8 @@ function rdf_preprocess_comment(&$variables) {
 
   // Annotates the parent relationship between the current comment and the node
   // it belongs to. If available, the parent comment is also annotated.
+  // @todo When comments are turned into fields, this should be changed.
+  // Currently there is no mapping relating a comment to its node.
   $pid_mapping = $mapping->getPreparedFieldMapping('pid');
   if (!empty($pid_mapping)) {
     // Adds the relation to the parent node.
diff --git a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
index 808fe2a..4bad46b 100644
--- a/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
+++ b/core/modules/rest/lib/Drupal/rest/Tests/RESTTestBase.php
@@ -166,11 +166,6 @@ protected function entityValues($entity_type) {
         );
       case 'node':
         return array('title' => $this->randomString(), 'type' => $this->randomString());
-      case 'node_type':
-        return array(
-          'type' => 'article',
-          'name' => $this->randomName(),
-        );
       case 'user':
         return array('name' => $this->randomName());
       default:
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php
index da0e616..d5a143d 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php
@@ -21,7 +21,7 @@ class ShortcutAccessController extends EntityAccessController {
    */
   protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
     switch ($operation) {
-      case 'update':
+      case 'edit':
         if (user_access('administer shortcuts', $account)) {
           return TRUE;
         }
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php
index 02e8e87..a40005c 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutListController.php
@@ -24,21 +24,22 @@ public function buildHeader() {
   }
 
   /**
-   * {@inheritdoc}
+   * Overrides \Drupal\Core\Entity\EntityListController::getOperations().
    */
   public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
     $uri = $entity->uri();
 
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('Edit menu');
-      $operations['edit']['href'] = $uri['path'] . '/edit';
-    }
+    $operations['edit']['title'] = t('Edit menu');
+    $operations['edit']['href'] = $uri['path'] . '/edit';
 
     $operations['list'] = array(
       'title' => t('List links'),
       'href' => $uri['path'],
     );
+    if (!$entity->access('delete')) {
+      unset($operations['delete']);
+    }
     return $operations;
   }
 
diff --git a/core/modules/shortcut/shortcut.routing.yml b/core/modules/shortcut/shortcut.routing.yml
index df1dc1c..b217514 100644
--- a/core/modules/shortcut/shortcut.routing.yml
+++ b/core/modules/shortcut/shortcut.routing.yml
@@ -24,11 +24,11 @@ shortcut_set_edit:
   defaults:
     _entity_form: 'shortcut.edit'
   requirements:
-    _entity_access: 'shortcut.update'
+    _entity_access: 'shortcut.edit'
 
 shortcut_link_add_inline:
   pattern: '/admin/config/user-interface/shortcut/manage/{shortcut}/add-link-inline'
   defaults:
     _controller: 'Drupal\shortcut\Controller\ShortcutController::addShortcutLinkInline'
   requirements:
-    _entity_access: 'shortcut.update'
+    _entity_access: 'shortcut.edit'
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
index a7be5be..4615b39 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/Tests/DrupalUnitTestBaseTest.php
@@ -110,7 +110,7 @@ function testEnableModulesInstallContainer() {
     // Install Node module.
     $this->enableModules(array('field_sql_storage', 'field', 'node'));
 
-    $this->installSchema('node', array('node', 'node_field_data'));
+    $this->installSchema('node', array('node_type', 'node', 'node_field_data'));
     // Perform an entity query against node.
     $query = \Drupal::entityQuery('node');
     // Disable node access checks, since User module is not enabled.
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 8e295b3..68708ad 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -292,32 +292,48 @@ protected function drupalCreateNode(array $settings = array()) {
   /**
    * Creates a custom content type based on default settings.
    *
-   * @param array $values
+   * @param $settings
    *   An array of settings to change from the defaults.
    *   Example: 'type' => 'foo'.
-   *
-   * @return \Drupal\node\Plugin\Core\Entity\NodeType
+   * @return
    *   Created content type.
    */
-  protected function drupalCreateContentType(array $values = array()) {
+  protected function drupalCreateContentType($settings = array()) {
     // Find a non-existent random type name.
-    if (!isset($values['type'])) {
-      do {
-        $id = strtolower($this->randomName(8));
-      } while (node_type_load($id));
-    }
-    else {
-      $id = $values['type'];
-    }
-    $values += array(
-      'type' => $id,
-      'name' => $id,
+    do {
+      $name = strtolower($this->randomName(8));
+    } while (node_type_load($name));
+
+    // Populate defaults array.
+    $defaults = array(
+      'type' => $name,
+      'name' => $name,
+      'base' => 'node_content',
+      'description' => '',
+      'help' => '',
+      'title_label' => 'Title',
+      'body_label' => 'Body',
+      'has_title' => 1,
+      'has_body' => 1,
     );
-    $type = entity_create('node_type', $values);
-    $status = $type->save();
+    // Imposed values for a custom type.
+    $forced = array(
+      'orig_type' => '',
+      'old_type' => '',
+      'module' => 'node',
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+    );
+    $type = $forced + $settings + $defaults;
+    $type = (object) $type;
+
+    $saved_type = node_type_save($type);
+    node_types_rebuild();
     menu_router_rebuild();
+    node_add_body_field($type);
 
-    $this->assertEqual($status, SAVED_NEW, t('Created content type %type.', array('%type' => $type->id())));
+    $this->assertEqual($saved_type, SAVED_NEW, t('Created content type %type.', array('%type' => $type->type)));
 
     // Reset permissions so that permissions for this content type are available.
     $this->checkPermissions(array(), TRUE);
diff --git a/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php b/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php
index fe8f537..dfdf379 100644
--- a/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php
+++ b/core/modules/system/lib/Drupal/system/Plugin/Core/Entity/Action.php
@@ -23,8 +23,7 @@
  *   label = @Translation("Action"),
  *   module = "system",
  *   controllers = {
- *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController",
- *     "access" = "Drupal\action\ActionAccessController"
+ *     "storage" = "Drupal\Core\Config\Entity\ConfigStorageController"
  *   },
  *   config_prefix = "action.action",
  *   entity_keys = {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php b/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
index 26ee375..e191efe 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Condition/ConditionFormTest.php
@@ -32,8 +32,6 @@ public static function getInfo() {
    * Submit the condition_node_type_test_form to test condition forms.
    */
   function testConfigForm() {
-    $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Page'));
-    $this->drupalCreateContentType(array('type' => 'article', 'name' => 'Article'));
     $article = entity_create('node', array('type' => 'article', 'title' => $this->randomName()));
     $article->save();
     $this->drupalGet('condition_test');
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
index 68b2525..0ba07bc 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityBCDecoratorTest.php
@@ -32,7 +32,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_roles', 'users_data'));
-    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
+    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
index 055b014..3649529 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityCrudHookTest.php
@@ -44,7 +44,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_roles', 'users_data'));
-    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
+    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
index 8e7eea4..48b04ba 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -36,7 +36,7 @@ public static function getInfo() {
   public function setUp() {
     parent::setUp();
     $this->installSchema('user', array('users_roles', 'users_data'));
-    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_access'));
+    $this->installSchema('node', array('node', 'node_field_data', 'node_field_revision', 'node_type', 'node_access'));
     $this->installSchema('entity_test', array(
       'entity_test_mul',
       'entity_test_mul_property_data',
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
index b04e2d8..5d5fb63 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -27,6 +27,11 @@ public static function getInfo() {
     );
   }
 
+  protected function setUp() {
+    parent::setUp();
+    $this->installSchema('node', 'node_type');
+  }
+
   /**
    * Tests basic context definition and value getters and setters.
    */
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 9fedb35..33f7903 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FilledStandardUpgradePathTest.php
@@ -95,10 +95,9 @@ public function testFilledStandardUpgrade() {
     $this->assertFalse($result, 'No {menu_links} entry exists for user/autocomplete');
 
     // Verify that the blog node type has been assigned to node module.
-    $node_type = entity_load('node_type', 'blog');
-    $this->assertFalse($node_type->isLocked(), "Content type 'blog' has been reassigned from the blog module to the node module.");
-    $node_type = entity_load('node_type', 'forum');
-    $this->assertTrue($node_type->isLocked(), "The base string used to construct callbacks corresponding to content type 'Forum' has been reassigned to forum module.");
+    $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'.");
 
     // Each entity type has a 'full' view mode, ensure it was migrated.
     $all_view_modes = entity_get_view_modes();
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
index dd9bcf9..376f1e9 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UserPictureUpgradePathTest.php
@@ -69,7 +69,7 @@ public function testUserPictureUpgrade() {
 
     // Check the user picture and file usage record.
     $user = user_load(1);
-    $file = file_load($user->user_picture[Language::LANGCODE_NOT_SPECIFIED][0]['target_id']);
+    $file = file_load($user->user_picture[Language::LANGCODE_NOT_SPECIFIED][0]['fid']);
     $this->assertEqual('public://user_pictures_dir/faked_image.png', $file->getFileUri());
     $usage = file_usage()->listUsage($file);
     $this->assertEqual(1, $usage['file']['user'][1]);
diff --git a/core/modules/system/system.api.php b/core/modules/system/system.api.php
index 36e9f77..e9e69c5 100644
--- a/core/modules/system/system.api.php
+++ b/core/modules/system/system.api.php
@@ -2416,7 +2416,7 @@ function hook_schema() {
         'default' => 0,
       ),
       'type' => array(
-        'description' => 'The type of this node.',
+        'description' => 'The {node_type} of this node.',
         'type' => 'varchar',
         'length' => 32,
         'not null' => TRUE,
diff --git a/core/modules/system/tests/modules/condition_test/condition_test.module b/core/modules/system/tests/modules/condition_test/condition_test.module
index b3d9bbc..1310b21 100644
--- a/core/modules/system/tests/modules/condition_test/condition_test.module
+++ b/core/modules/system/tests/modules/condition_test/condition_test.module
@@ -1 +1,21 @@
 <?php
+
+/**
+ * Implements hook_node_info().
+ */
+function condition_test_node_info() {
+  return array(
+    'article' => array(
+      'name' => t('Article'),
+      'base' => 'article',
+      'description' => t('An article content type'),
+      'title_label' => t('Subject'),
+    ),
+    'page' => array(
+      'name' => t('Page'),
+      'base' => 'page',
+      'description' => t('A page content type'),
+      'title_label' => t('Subject'),
+    ),
+  );
+}
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
index 332b322..6ce0c1b 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTest.php
@@ -29,11 +29,10 @@
  *   },
  *   base_table = "entity_test",
  *   fieldable = TRUE,
- *   field_cache = FALSE,
  *   entity_keys = {
  *     "id" = "id",
  *     "uuid" = "uuid",
- *     "bundle" = "type",
+ *     "bundle" = "type"
  *   },
  *   menu_base_path = "entity-test/manage/%entity_test"
  * )
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestCache.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestCache.php
deleted file mode 100644
index 615bffc..0000000
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/Plugin/Core/Entity/EntityTestCache.php
+++ /dev/null
@@ -1,103 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\entity_test\Plugin\Core\Entity\EntityTestCache.
- */
-
-namespace Drupal\entity_test\Plugin\Core\Entity;
-
-use Drupal\Core\Entity\EntityNG;
-use Drupal\Core\Entity\Annotation\EntityType;
-use Drupal\Core\Annotation\Translation;
-use Drupal\Core\Language\Language;
-
-/**
- * Defines the test entity class.
- *
- * @EntityType(
- *   id = "entity_test_cache",
- *   label = @Translation("Test entity with field cache"),
- *   module = "entity_test",
- *   controllers = {
- *     "storage" = "Drupal\entity_test\EntityTestStorageController",
- *     "access" = "Drupal\entity_test\EntityTestAccessController",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestFormController"
- *     },
- *     "translation" = "Drupal\translation_entity\EntityTranslationControllerNG"
- *   },
- *   base_table = "entity_test",
- *   fieldable = TRUE,
- *   field_cache = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type"
- *   },
- *   menu_base_path = "entity-test/manage/%entity_test"
- * )
- */
-class EntityTestCache extends EntityNG {
-
-  /**
-   * The entity ID.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $id;
-
-  /**
-   * The entity UUID.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $uuid;
-
-  /**
-   * The bundle of the test entity.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $type;
-
-  /**
-   * The name of the test entity.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $name;
-
-  /**
-   * The associated user.
-   *
-   * @var \Drupal\Core\Entity\Field\FieldInterface
-   */
-  public $user_id;
-
-  /**
-   * Initialize the object. Invoked upon construction and wake up.
-   */
-  protected function init() {
-    parent::init();
-    // We unset all defined properties, so magic getters apply.
-    unset($this->id);
-    unset($this->uuid);
-    unset($this->name);
-    unset($this->user_id);
-    unset($this->type);
-  }
-
-  /**
-   * Overrides Drupal\entity\Entity::label().
-   */
-  public function label($langcode = Language::LANGCODE_DEFAULT) {
-    $info = $this->entityInfo();
-    if (isset($info['entity_keys']['label']) && $info['entity_keys']['label'] == 'name') {
-      return $this->getTranslation($langcode)->name->value;
-    }
-    else {
-      return parent::label($langcode);
-    }
-  }
-}
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php
index 8fa30c3..db7571d 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/TermIndexTest.php
@@ -151,8 +151,9 @@ function testTaxonomyIndex() {
     $this->assertEqual(1, $index_count, 'Term 2 is indexed once.');
 
     // Redo the above tests without interface.
-    $node = node_load($node->id(), TRUE);
     $node->title = $this->randomName();
+    unset($node->{$this->field_name_1});
+    unset($node->{$this->field_name_2});
 
     // Update the article with no term changed.
     $node->save();
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
index e7c7031..4e23cd8 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Tests/Views/TaxonomyTestBase.php
@@ -67,9 +67,14 @@ function setUp() {
    * @see http://drupal.org/node/1708692
    */
   protected function mockStandardInstall() {
-    $type = $this->drupalCreateContentType(array(
+    $type = array(
       'type' => 'article',
-    ));
+    );
+
+    $type = node_type_set_defaults($type);
+    node_type_save($type);
+    node_add_body_field($type);
+
     // Create the vocabulary for the tag field.
     $this->vocabulary = entity_create('taxonomy_vocabulary',  array(
       'name' => 'Views testing tags',
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
index 21c210b..082ed5d 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Type/TaxonomyTermReferenceItem.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\taxonomy\Type;
 
+use Drupal\Core\Entity\Field\Type\EntityReferenceItem;
 use Drupal\field\Plugin\Type\FieldType\ConfigEntityReferenceItemBase;
 
 /**
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php
index edd0b8d..11ed4a1 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyListController.php
@@ -30,10 +30,8 @@ public function getOperations(EntityInterface $entity) {
     $operations = parent::getOperations($entity);
     $uri = $entity->uri();
 
-    if (isset($operations['edit'])) {
-      $operations['edit']['title'] = t('edit vocabulary');
-      $operations['edit']['href'] = $uri['path'] . '/edit';
-    }
+    $operations['edit']['title'] = t('edit vocabulary');
+    $operations['edit']['href'] = $uri['path'] . '/edit';
 
     $operations['list'] = array(
       'title' => t('list terms'),
diff --git a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php
index 5716978..d4f85b8 100644
--- a/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php
+++ b/core/modules/toolbar/lib/Drupal/toolbar/Tests/ToolbarHookToolbarTest.php
@@ -50,14 +50,8 @@ function testHookToolbar() {
     // Assert that the tab registered by toolbar_test is present.
     $this->assertRaw('id="toolbar-tab-testing"');
 
-    // Assert that the tab item descriptions are present.
-    $this->assertRaw('title="Test tab"');
-
     // Assert that the tray registered by toolbar_test is present.
     $this->assertRaw('id="toolbar-tray-testing"');
-
-    // Assert that tray item descriptions are present.
-    $this->assertRaw('title="Test link 1 title"');
   }
 
 }
diff --git a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
index 3ccbf0a..ab7c2ad 100644
--- a/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
+++ b/core/modules/toolbar/tests/modules/toolbar_test/toolbar_test.module
@@ -31,9 +31,9 @@ function toolbar_test_toolbar() {
       'content' => array(
         '#theme' => 'item_list',
         '#items' => array(
-          l(t('link 1'), '<front>', array('attributes' => array('title' => 'Test link 1 title'))),
-          l(t('link 2'), '<front>', array('attributes' => array('title' => 'Test link 2 title'))),
-          l(t('link 3'), '<front>', array('attributes' => array('title' => 'Test link 3 title'))),
+          l(t('link 1'), '<front>'),
+          l(t('link 2'), '<front>'),
+          l(t('link 3'), '<front>'),
         ),
         '#prefix' => '<h2 class="visually-hidden">' . t('Test tray') . '</h2>',
         '#attributes' => array(
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 14135bb..52d3988 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -515,7 +515,6 @@ function toolbar_menu_navigation_links(&$tree) {
         'icon',
         'icon-' . strtolower(str_replace(' ', '-', $item['link']['link_title'])),
       ),
-      'title' => check_plain($item['link']['description']),
     );
   }
 }
diff --git a/core/modules/translation/translation.module b/core/modules/translation/translation.module
index 2d50934..e8e872e 100644
--- a/core/modules/translation/translation.module
+++ b/core/modules/translation/translation.module
@@ -166,7 +166,7 @@ function translation_form_node_type_form_alter(&$form, &$form_state) {
   $form['language']['node_type_language_translation_enabled'] = array(
     '#type' => 'checkbox',
     '#title' => t('Enable translation'),
-    '#default_value' => variable_get('node_type_language_translation_enabled_' . $form_state['controller']->getEntity()->id(), FALSE),
+    '#default_value' => variable_get('node_type_language_translation_enabled_' . $form['#node_type']->type, FALSE),
     '#element_validate' => array('translation_node_type_language_translation_enabled_validate'),
     '#prefix' => "<label class='form-item-node-type-language-translation-enabled'>" . t('Translation') . "</label>",
   );
diff --git a/core/modules/user/config/rdf.mapping.user.user.yml b/core/modules/user/config/rdf.mapping.user.user.yml
new file mode 100644
index 0000000..ad082a9
--- /dev/null
+++ b/core/modules/user/config/rdf.mapping.user.user.yml
@@ -0,0 +1,9 @@
+id: user.user
+targetEntityType: user
+bundle: user
+types:
+  - 'schema:Person'
+fieldMappings:
+  name:
+    properties:
+      - 'schema:name'
diff --git a/core/modules/user/lib/Drupal/user/Controller/UserController.php b/core/modules/user/lib/Drupal/user/Controller/UserController.php
index eb1dbde..e782019 100644
--- a/core/modules/user/lib/Drupal/user/Controller/UserController.php
+++ b/core/modules/user/lib/Drupal/user/Controller/UserController.php
@@ -7,38 +7,27 @@
 
 namespace Drupal\user\Controller;
 
-use Drupal\user\Form\UserLoginForm;
-use Symfony\Component\DependencyInjection\ContainerAware;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Controller\ControllerInterface;
 
 /**
  * Controller routines for user routes.
  */
-class UserController extends ContainerAware {
+class UserController implements ControllerInterface {
 
   /**
-   * Returns the user page.
-   *
-   * Displays user profile if user is logged in, or login form for anonymous
-   * users.
-   *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object.
-   *
-   * @return \Symfony\Component\HttpFoundation\RedirectResponse|array
-   *   Returns either a redirect to the user page or the render
-   *   array of the login form.
+   * Constructs an UserController object.
+   */
+  public function __construct() {
+  }
+
+  /**
+   * {@inheritdoc}
    */
-  public function userPage(Request $request) {
-    global $user;
-    if ($user->uid) {
-      $response = new RedirectResponse(url('user/' . $user->uid, array('absolute' => TRUE)));
-    }
-    else {
-      $response = drupal_get_form(UserLoginForm::create($this->container), $request);
-    }
-    return $response;
+  public static function create(ContainerInterface $container) {
+    return new static();
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php b/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
deleted file mode 100644
index 93236f1..0000000
--- a/core/modules/user/lib/Drupal/user/Form/UserLoginForm.php
+++ /dev/null
@@ -1,243 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\user\Form\UserLoginForm.
- */
-
-namespace Drupal\user\Form;
-
-use Drupal\Core\Config\ConfigFactory;
-use Drupal\Core\Controller\ControllerInterface;
-use Drupal\Core\Database\Connection;
-use Drupal\Core\Flood\FloodInterface;
-use Drupal\Core\Form\FormInterface;
-use Drupal\user\UserStorageControllerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
-
-/**
- * Provides a user login form.
- */
-class UserLoginForm implements FormInterface, ControllerInterface {
-
-  /**
-   * The config factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactory
-   */
-  protected $configFactory;
-
-  /**
-   * The request object.
-   *
-   * @var \Symfony\Component\HttpFoundation\Request
-   */
-  protected $request;
-
-  /**
-   * The flood service.
-   *
-   * @var \Drupal\Core\Flood\FloodInterface
-   */
-  protected $flood;
-
-  /**
-   * The user storage controller.
-   *
-   * @var \Drupal\user\UserStorageControllerInterface
-   */
-  protected $storageController;
-
-  /**
-   * Constructs a new UserLoginForm.
-   *
-   * @param \Drupal\Core\Config\ConfigFactory $config_factory
-   *   The config factory.
-   * @param \Drupal\Core\Flood\FloodInterface $flood
-   *   The flood service.
-   * @param \Drupal\user\UserStorageControllerInterface $storage_controller
-   *   The user storage controller.
-   */
-  public function __construct(ConfigFactory $config_factory, FloodInterface $flood, UserStorageControllerInterface $storage_controller) {
-    $this->configFactory = $config_factory;
-    $this->flood = $flood;
-    $this->storageController = $storage_controller;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container) {
-    return new static(
-      $container->get('config.factory'),
-      $container->get('flood'),
-      $container->get('plugin.manager.entity')->getStorageController('user')
-    );
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function getFormID() {
-    return 'user_login_form';
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function buildForm(array $form, array &$form_state, Request $request = NULL) {
-    $this->request = $request;
-    // Display login form:
-    $form['name'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Username'),
-      '#size' => 60,
-      '#maxlength' => USERNAME_MAX_LENGTH,
-      '#description' => t('Enter your @s username.', array('@s' => $this->configFactory->get('system.site')->get('name'))),
-      '#required' => TRUE,
-      '#attributes' => array(
-        'autocorrect' => 'off',
-        'autocapitalize' => 'off',
-        'spellcheck' => 'false',
-        'autofocus' => 'autofocus',
-      ),
-    );
-
-    $form['pass'] = array(
-      '#type' => 'password',
-      '#title' => t('Password'),
-      '#size' => 60,
-      '#description' => t('Enter the password that accompanies your username.'),
-      '#required' => TRUE,
-    );
-
-    $form['actions'] = array('#type' => 'actions');
-    $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
-
-    $form['#validate'][] = array($this, 'validateName');
-    $form['#validate'][] = array($this, 'validateAuthentication');
-    $form['#validate'][] = array($this, 'validateFinal');
-
-    return $form;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function validateForm(array &$form, array &$form_state) {
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public function submitForm(array &$form, array &$form_state) {
-    $accounts = $this->storageController->load(array($form_state['uid']));
-    $account = reset($accounts)->getBCEntity();
-    $form_state['redirect'] = 'user/' . $account->id();
-
-    user_login_finalize($account);
-  }
-
-  /**
-   * Sets an error if supplied username has been blocked.
-   */
-  public function validateName(array &$form, array &$form_state) {
-    if (!empty($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
-      // Blocked in user administration.
-      form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
-    }
-  }
-
-  /**
-   * Checks supplied username/password against local users table.
-   *
-   * If successful, $form_state['uid'] is set to the matching user ID.
-   */
-  public function validateAuthentication(array &$form, array &$form_state) {
-    $password = trim($form_state['values']['pass']);
-    $flood_config = $this->configFactory->get('user.flood');
-    if (!empty($form_state['values']['name']) && !empty($password)) {
-      // Do not allow any login from the current user's IP if the limit has been
-      // reached. Default is 50 failed attempts allowed in one hour. This is
-      // independent of the per-user limit to catch attempts from one IP to log
-      // in to many different user accounts.  We have a reasonably high limit
-      // since there may be only one apparent IP for all users at an institution.
-      if (!$this->flood->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
-        $form_state['flood_control_triggered'] = 'ip';
-        return;
-      }
-      $accounts = $this->storageController->loadByProperties(array('name' => $form_state['values']['name'], 'status' => 1));
-      $account = reset($accounts);
-      if ($account) {
-        if ($flood_config->get('uid_only')) {
-          // Register flood events based on the uid only, so they apply for any
-          // IP address. This is the most secure option.
-          $identifier = $account->id();
-        }
-        else {
-          // The default identifier is a combination of uid and IP address. This
-          // is less secure but more resistant to denial-of-service attacks that
-          // could lock out all users with public user names.
-          $identifier = $account->id() . '-' . $this->request->getClientIP();
-        }
-        $form_state['flood_control_user_identifier'] = $identifier;
-
-        // Don't allow login if the limit for this user has been reached.
-        // Default is to allow 5 failed attempts every 6 hours.
-        if (!$this->flood->isAllowed('user.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
-          $form_state['flood_control_triggered'] = 'user';
-          return;
-        }
-      }
-      // We are not limited by flood control, so try to authenticate.
-      // Set $form_state['uid'] as a flag for user_login_final_validate().
-      $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
-    }
-  }
-
-  /**
-   * Checks if user was not authenticated, or if too many logins were attempted.
-   *
-   * This validation function should always be the last one.
-   */
-  public function validateFinal(array &$form, array &$form_state) {
-    $flood_config = $this->configFactory->get('user.flood');
-    if (empty($form_state['uid'])) {
-      // Always register an IP-based failed login event.
-      $this->flood->register('user.failed_login_ip', $flood_config->get('ip_window'));
-      // Register a per-user failed login event.
-      if (isset($form_state['flood_control_user_identifier'])) {
-        $this->flood->register('user.failed_login_user', $flood_config->get('user_window'), $form_state['flood_control_user_identifier']);
-      }
-
-      if (isset($form_state['flood_control_triggered'])) {
-        if ($form_state['flood_control_triggered'] == 'user') {
-          form_set_error('name', format_plural($flood_config->get('user_limit'), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
-        }
-        else {
-          // We did not find a uid, so the limit is IP-based.
-          form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
-        }
-      }
-      else {
-        form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => array('name' => $form_state['values']['name']))))));
-        $accounts = $this->storageController->loadByProperties(array('name' => $form_state['values']['name']));
-        if (!empty($accounts)) {
-          watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
-        }
-        else {
-          // If the username entered is not a valid user,
-          // only store the IP address.
-          watchdog('user', 'Login attempt failed from %ip.', array('%ip' => $this->request->getClientIp()));
-        }
-      }
-    }
-    elseif (isset($form_state['flood_control_user_identifier'])) {
-      // Clear past failures for this user so as not to block a user who might
-      // log in and out more than once in an hour.
-      $this->flood->clear('user.failed_login_user', $form_state['flood_control_user_identifier']);
-    }
-  }
-
-}
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php b/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php
index 0cc09b7..0c8aa2a 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Block/UserLoginBlock.php
@@ -10,11 +10,6 @@
 use Drupal\block\BlockBase;
 use Drupal\Component\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
-use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
-use Drupal\user\Form\UserLoginForm;
-use Symfony\Component\DependencyInjection\ContainerAwareInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Provides a 'User login' block.
@@ -25,55 +20,7 @@
  *   module = "user"
  * )
  */
-class UserLoginBlock extends BlockBase implements ContainerFactoryPluginInterface {
-
-  /**
-   * The DI Container.
-   *
-   * @var \Symfony\Component\DependencyInjection\ContainerInterface
-   */
-  protected $container;
-
-  /**
-   * The request object.
-   *
-   * @var \Symfony\Component\HttpFoundation\Request
-   */
-  protected $request;
-
-  /**
-   * Constructs a new UserLoginBlock.
-   *
-   * @param array $configuration
-   *   A configuration array containing information about the plugin instance.
-   * @param string $plugin_id
-   *   The plugin ID for the plugin instance.
-   * @param array $plugin_definition
-   *   The plugin implementation definition.
-   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
-   *   The DI Container.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object.
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, ContainerInterface $container, Request $request) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->container = $container;
-    $this->request = $request;
-  }
-
-  /**
-   * {@inheritdo}
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
-    return new static(
-      $configuration,
-      $plugin_id,
-      $plugin_definition,
-      $container,
-      $container->get('request')
-    );
-  }
+class UserLoginBlock extends BlockBase {
 
   /**
    * Overrides \Drupal\block\BlockBase::access().
@@ -86,7 +33,7 @@ public function access() {
    * {@inheritdoc}
    */
   public function build() {
-    $form = drupal_get_form(UserLoginForm::create($this->container), $this->request);
+    $form = drupal_get_form('user_login_form');
     unset($form['name']['#attributes']['autofocus']);
     unset($form['name']['#description']);
     unset($form['pass']['#description']);
diff --git a/core/modules/user/lib/Drupal/user/RegisterFormController.php b/core/modules/user/lib/Drupal/user/RegisterFormController.php
index f9f6b67..7d22cd3 100644
--- a/core/modules/user/lib/Drupal/user/RegisterFormController.php
+++ b/core/modules/user/lib/Drupal/user/RegisterFormController.php
@@ -120,7 +120,8 @@ public function save(array $form, array &$form_state) {
     // No e-mail verification required; log in user immediately.
     elseif (!$admin && !config('user.settings')->get('verify_mail') && $account->status) {
       _user_mail_notify('register_no_approval_required', $account);
-      user_login_finalize($account);
+      $form_state['uid'] = $account->uid;
+      user_login_form_submit(array(), $form_state);
       drupal_set_message(t('Registration successful. You are now logged in.'));
       $form_state['redirect'] = '';
     }
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php
index 09a2cf4..7583cb8 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPasswordResetTest.php
@@ -39,14 +39,6 @@ public function setUp() {
 
     $this->account = user_load($account->uid);
     $this->drupalLogout();
-
-    // Set the last login time that is used to generate the one-time link so
-    // that it is definitely over a second ago.
-    $account->login = REQUEST_TIME - mt_rand(10, 100000);
-    db_update('users')
-      ->fields(array('login' => $account->login))
-      ->condition('uid', $account->uid)
-      ->execute();
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
index 282dd65..633e0cf 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPictureTest.php
@@ -135,6 +135,6 @@ function saveUserPicture($image) {
 
     // Load actual user data from database.
     $account = user_load($this->web_user->uid, TRUE);
-    return file_load($account->user_picture[Language::LANGCODE_NOT_SPECIFIED][0]['target_id'], TRUE);
+    return file_load($account->user_picture[Language::LANGCODE_NOT_SPECIFIED][0]['fid'], TRUE);
   }
 }
diff --git a/core/modules/user/user.install b/core/modules/user/user.install
index 454c628..361a3e4 100644
--- a/core/modules/user/user.install
+++ b/core/modules/user/user.install
@@ -273,7 +273,7 @@ function user_install_picture_field() {
     'type' => 'image',
     'cardinality' => 1,
     'locked' => FALSE,
-    'indexes' => array('target_id' => array('target_id')),
+    'indexes' => array('fid' => array('fid')),
     'settings' => array(
       'uri_scheme' => 'public',
       'default_image' => FALSE,
@@ -660,7 +660,7 @@ function user_update_8011() {
     'type' => 'image',
     'cardinality' => 1,
     'locked' => FALSE,
-    'indexes' => array('target_id' => array('target_id')),
+    'indexes' => array('fid' => array('fid')),
     'settings' => array(
       'uri_scheme' => 'public',
       'default_image' => FALSE,
@@ -783,7 +783,7 @@ function user_update_8012(&$sandbox) {
           'revision_id' => $uid,
           'langcode' => Language::LANGCODE_NOT_SPECIFIED,
           'delta' => 0,
-          'user_picture_target_id' => $fid,
+          'user_picture_fid' => $fid,
         ))
         ->execute();
       db_insert('field_revision_user_picture')
@@ -794,7 +794,7 @@ function user_update_8012(&$sandbox) {
           'revision_id' => $uid,
           'langcode' => Language::LANGCODE_NOT_SPECIFIED,
           'delta' => 0,
-          'user_picture_target_id' => $fid,
+          'user_picture_fid' => $fid,
         ))
         ->execute();
 
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 74d3743..aecb7e7 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -850,13 +850,16 @@ function user_menu() {
   $items['user'] = array(
     'title' => 'User account',
     'title callback' => 'user_menu_title',
+    'page callback' => 'user_page',
+    'access callback' => TRUE,
+    'file' => 'user.pages.inc',
     'weight' => -10,
-    'route_name' => 'user_page',
     'menu_name' => 'account',
   );
 
   $items['user/login'] = array(
     'title' => 'Log in',
+    'access callback' => 'user_is_anonymous',
     'type' => MENU_DEFAULT_LOCAL_TASK,
   );
   // Other authentication methods may add pages below user/login/.
@@ -1148,6 +1151,44 @@ function user_page_title($account) {
 }
 
 /**
+ * Form builder; the main user login form.
+ *
+ * @ingroup forms
+ */
+function user_login_form($form, &$form_state) {
+  // Display login form:
+  $form['name'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Username'),
+    '#size' => 60,
+    '#maxlength' => USERNAME_MAX_LENGTH,
+    '#description' => t('Enter your @s username.', array('@s' => config('system.site')->get('name'))),
+    '#required' => TRUE,
+    '#attributes' => array(
+      'autocorrect' => 'off',
+      'autocapitalize' => 'off',
+      'spellcheck' => 'false',
+      'autofocus' => 'autofocus',
+    ),
+  );
+
+  $form['pass'] = array(
+    '#type' => 'password',
+    '#title' => t('Password'),
+    '#size' => 60,
+    '#description' => t('Enter the password that accompanies your username.'),
+    '#required' => TRUE,
+  );
+
+  $form['actions'] = array('#type' => 'actions');
+  $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Log in'));
+
+  $form['#validate'] = user_login_default_validators();
+
+  return $form;
+}
+
+/**
  * Set up a series for validators which check for blocked users,
  * then authenticate against local database, then return an error if
  * authentication fails. Distributed authentication modules are welcome
@@ -1170,6 +1211,109 @@ function user_login_default_validators() {
 }
 
 /**
+ * A FAPI validate handler. Sets an error if supplied username has been blocked.
+ */
+function user_login_name_validate($form, &$form_state) {
+  if (!empty($form_state['values']['name']) && user_is_blocked($form_state['values']['name'])) {
+    // Blocked in user administration.
+    form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name'])));
+  }
+}
+
+/**
+ * A validate handler on the login form. Check supplied username/password
+ * against local users table. If successful, $form_state['uid']
+ * is set to the matching user ID.
+ */
+function user_login_authenticate_validate($form, &$form_state) {
+  $password = trim($form_state['values']['pass']);
+  $flood_config = config('user.flood');
+  $flood = Drupal::service('flood');
+  if (!empty($form_state['values']['name']) && !empty($password)) {
+    // Do not allow any login from the current user's IP if the limit has been
+    // reached. Default is 50 failed attempts allowed in one hour. This is
+    // independent of the per-user limit to catch attempts from one IP to log
+    // in to many different user accounts.  We have a reasonably high limit
+    // since there may be only one apparent IP for all users at an institution.
+    if (!$flood->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
+      $form_state['flood_control_triggered'] = 'ip';
+      return;
+    }
+    $account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1", array(':name' => $form_state['values']['name']))->fetchObject();
+    if ($account) {
+      if ($flood_config->get('uid_only')) {
+        // Register flood events based on the uid only, so they apply for any
+        // IP address. This is the most secure option.
+        $identifier = $account->uid;
+      }
+      else {
+        // The default identifier is a combination of uid and IP address. This
+        // is less secure but more resistant to denial-of-service attacks that
+        // could lock out all users with public user names.
+        $identifier = $account->uid . '-' . Drupal::request()->getClientIP();
+      }
+      $form_state['flood_control_user_identifier'] = $identifier;
+
+      // Don't allow login if the limit for this user has been reached.
+      // Default is to allow 5 failed attempts every 6 hours.
+      if (!$flood->isAllowed('user.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
+        $form_state['flood_control_triggered'] = 'user';
+        return;
+      }
+    }
+    // We are not limited by flood control, so try to authenticate.
+    // Set $form_state['uid'] as a flag for user_login_final_validate().
+    $form_state['uid'] = user_authenticate($form_state['values']['name'], $password);
+  }
+}
+
+/**
+ * The final validation handler on the login form.
+ *
+ * Sets a form error if user has not been authenticated, or if too many
+ * logins have been attempted. This validation function should always
+ * be the last one.
+ */
+function user_login_final_validate($form, &$form_state) {
+  $flood_config = config('user.flood');
+  $flood = Drupal::service('flood');
+  if (empty($form_state['uid'])) {
+    // Always register an IP-based failed login event.
+    $flood->register('user.failed_login_ip', $flood_config->get('ip_window'));
+    // Register a per-user failed login event.
+    if (isset($form_state['flood_control_user_identifier'])) {
+      $flood->register('user.failed_login_user', $flood_config->get('user_window'), $form_state['flood_control_user_identifier']);
+    }
+
+    if (isset($form_state['flood_control_triggered'])) {
+      if ($form_state['flood_control_triggered'] == 'user') {
+        form_set_error('name', format_plural($flood_config->get('user_limit'), 'Sorry, there has been more than one failed login attempt for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', 'Sorry, there have been more than @count failed login attempts for this account. It is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
+      }
+      else {
+        // We did not find a uid, so the limit is IP-based.
+        form_set_error('name', t('Sorry, too many failed login attempts from your IP address. This IP address is temporarily blocked. Try again later or <a href="@url">request a new password</a>.', array('@url' => url('user/password'))));
+      }
+    }
+    else {
+      form_set_error('name', t('Sorry, unrecognized username or password. <a href="@password">Have you forgotten your password?</a>', array('@password' => url('user/password', array('query' => array('name' => $form_state['values']['name']))))));
+      if (user_load_by_name($form_state['values']['name'])) {
+        watchdog('user', 'Login attempt failed for %user.', array('%user' => $form_state['values']['name']));
+      }
+      else {
+        // If the username entered is not a valid user,
+        // only store the IP address.
+        watchdog('user', 'Login attempt failed from %ip.', array('%ip' => Drupal::request()->getClientIp()));
+      }
+    }
+  }
+  elseif (isset($form_state['flood_control_user_identifier'])) {
+    // Clear past failures for this user so as not to block a user who might
+    // log in and out more than once in an hour.
+    $flood->clear('user.failed_login_user', $form_state['flood_control_user_identifier']);
+  }
+}
+
+/**
  * Try to validate the user's login credentials locally.
  *
  * @param $name
@@ -1201,22 +1345,18 @@ function user_authenticate($name, $password) {
 }
 
 /**
- * Finalizes the login process and logs in a user.
+ * Finalize the login process. Must be called when logging in a user.
  *
- * The function logs in the user, records a watchdog message about the new
- * session, saves the login timestamp, calls hook_user_login(), and generates a
- * new session.
+ * The function records a watchdog message about the new session, saves the
+ * login timestamp, calls hook_user_login(), and generates a new session.
  *
- * The global $user object is replaced with the passed in account.
- *
- * @param \Drupal\Core\Session\AccountInterface $account
- *   The account to log in.
+ * @param array $edit
+ *   The array of form values submitted by the user.
  *
  * @see hook_user_login()
  */
-function user_login_finalize(AccountInterface $account) {
+function user_login_finalize(&$edit = array()) {
   global $user;
-  $user = $account;
   watchdog('user', 'Session opened for %name.', array('%name' => $user->name));
   // Update the user table timestamp noting user has logged in.
   // This is also used to invalidate one-time login links.
@@ -1235,6 +1375,19 @@ function user_login_finalize(AccountInterface $account) {
 }
 
 /**
+ * Submit handler for the login form. Load $user object and perform standard login
+ * tasks. The user is then redirected to the My Account page. Setting the
+ * destination in the query string overrides the redirect.
+ */
+function user_login_form_submit($form, &$form_state) {
+  global $user;
+  $user = user_load($form_state['uid']);
+  $form_state['redirect'] = 'user/' . $user->uid;
+
+  user_login_finalize($form_state);
+}
+
+/**
  * Implements hook_user_login().
  */
 function user_user_login($account) {
@@ -2177,6 +2330,21 @@ function user_modules_uninstalled($modules) {
 }
 
 /**
+ * Helper function to rewrite the destination to avoid redirecting to login page after login.
+ *
+ * Third-party authentication modules may use this function to determine the
+ * proper destination after a user has been properly logged in.
+ */
+function user_login_destination() {
+  $destination = drupal_get_destination();
+  // Modules may provide login pages under the "user/login/" path prefix.
+  if (preg_match('@^user/login(/.*|)$@', $destination['destination'])) {
+    $destination['destination'] = 'user';
+  }
+  return $destination;
+}
+
+/**
  * Saves visitor information as a cookie so it can be reused.
  *
  * @param $values
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index f5f164f..5025c17 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -53,9 +53,10 @@ function user_pass_reset($form, &$form_state, $uid, $timestamp, $hashed_pass, $a
         // First stage is a confirmation form, then login
         if ($action == 'login') {
           // Set the new user.
+          $user = $account;
           // user_login_finalize() also updates the login timestamp of the
           // user, which invalidates further use of the one-time login link.
-          user_login_finalize($account);
+          user_login_finalize();
           watchdog('user', 'User %name used one-time login link at time %timestamp.', array('%name' => $account->name, '%timestamp' => $timestamp));
           drupal_set_message(t('You have just used your one-time login link. It is no longer necessary to use this link to log in. Please change your password.'));
           // Let the user's password be changed without the current password check.
@@ -323,3 +324,19 @@ function user_cancel_confirm($account, $timestamp = 0, $hashed_pass = '') {
   }
   throw new AccessDeniedHttpException();
 }
+
+/**
+ * Access callback for path /user.
+ *
+ * Displays user profile if user is logged in, or login form for anonymous
+ * users.
+ */
+function user_page() {
+  global $user;
+  if ($user->uid) {
+    return new RedirectResponse(url('user/' . $user->uid, array('absolute' => TRUE)));
+  }
+  else {
+    return drupal_get_form('user_login_form');
+  }
+}
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index 10ec95d..3d52545 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -74,17 +74,3 @@ user_pass:
     _form: '\Drupal\user\Form\UserPasswordForm'
   requirements:
     _access: 'TRUE'
-
-user_page:
-  pattern: '/user'
-  defaults:
-    _content: '\Drupal\user\Controller\UserController::userPage'
-  requirements:
-    _access: 'TRUE'
-
-user_login:
-  pattern: '/user/login'
-  defaults:
-    _form: '\Drupal\user\Form\UserLoginForm'
-  requirements:
-    _access: 'TRUE'
diff --git a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php
index 3923703..4b11a10 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/Core/Entity/View.php
@@ -24,8 +24,7 @@
  *   label = @Translation("View"),
  *   module = "views",
  *   controllers = {
- *     "storage" = "Drupal\views\ViewStorageController",
- *     "access" = "Drupal\views\ViewAccessController"
+ *     "storage" = "Drupal\views\ViewStorageController"
  *   },
  *   config_prefix = "views.view",
  *   entity_keys = {
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/argument_default/Raw.php b/core/modules/views/lib/Drupal/views/Plugin/views/argument_default/Raw.php
index 004cedf..25daa42 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/argument_default/Raw.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/argument_default/Raw.php
@@ -9,9 +9,6 @@
 
 use Drupal\Component\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
-use Drupal\Core\Path\AliasManagerInterface;
-use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Default argument plugin to use the raw value from the URL.
@@ -25,54 +22,6 @@
  */
 class Raw extends ArgumentDefaultPluginBase {
 
-  /**
-   * The request object.
-   *
-   * @var \Symfony\Component\HttpFoundation\Request
-   */
-  protected $request;
-
-  /**
-   * The alias manager.
-   *
-   * @var \Drupal\Core\Path\AliasManagerInterface
-   */
-  protected $aliasManager;
-
-  /**
-   * Constructs a Raw object.
-   *
-   * @param array $configuration
-   *   A configuration array containing information about the plugin instance.
-   * @param string $plugin_id
-   *   The plugin_id for the plugin instance.
-   * @param array $plugin_definition
-   *   The plugin implementation definition.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object.
-   * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
-   *   The alias manager.
-   */
-  public function __construct(array $configuration, $plugin_id, array $plugin_definition, Request $request, AliasManagerInterface $alias_manager) {
-    parent::__construct($configuration, $plugin_id, $plugin_definition);
-
-    $this->request = $request;
-    $this->aliasManager = $alias_manager;
-  }
-
-  /**
-   * {@inheritdoc}
-   */
-  public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) {
-    return new static(
-      $configuration,
-      $plugin_id,
-      $plugin_definition,
-      $container->get('request'),
-      $container->get('path.alias_manager.cached')
-    );
-  }
-
   protected function defineOptions() {
     $options = parent::defineOptions();
     $options['index'] = array('default' => '');
@@ -101,13 +50,12 @@ public function buildOptionsForm(&$form, &$form_state) {
   }
 
   public function getArgument() {
-    $path = $this->request->attributes->get('system_path');
+    $path = NULL;
     if ($this->options['use_alias']) {
-      $path = $this->aliasManager->getPathAlias($path);
+      $path = drupal_get_path_alias();
     }
-    $args = explode('/', $path);
-    if (isset($args[$this->options['index']])) {
-      return $args[$this->options['index']];
+    if ($arg = arg($this->options['index'], $path)) {
+      return $arg;
     }
   }
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
index 37d4d81..894363d 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewExecutableTest.php
@@ -81,7 +81,7 @@ public static function getInfo() {
 
   protected function setUpFixtures() {
     $this->installSchema('user', array('users'));
-    $this->installSchema('node', array('node', 'node_field_data'));
+    $this->installSchema('node', array('node_type', 'node', 'node_field_data'));
     $this->installSchema('comment', array('comment', 'node_comment_statistics'));
     parent::setUpFixtures();
 
diff --git a/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php b/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php
index fdd8d54..9ba340f 100644
--- a/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/ViewsTaxonomyAutocompleteTest.php
@@ -7,44 +7,22 @@
 
 namespace Drupal\views\Tests;
 
-use Drupal\views\Tests\ViewTestBase;
+use Drupal\taxonomy\Tests\Views\TaxonomyTestBase;
 use Drupal\Component\Utility\MapArray;
-use Drupal\Core\Language\Language;
 
 /**
  * Tests the views taxonomy complete menu callback.
  *
  * @see views_ajax_autocomplete_taxonomy()
  */
-class ViewsTaxonomyAutocompleteTest extends ViewTestBase {
-
-  /**
-   * The taxonomy vocabulary created for this test.
-   *
-   * @var \Drupal\taxonomy\VocabularyInterface
-   */
-  protected $vocabulary;
-
-  /**
-   * Stores the first term used in the different tests.
-   *
-   * @var \Drupal\taxonomy\TermInterface
-   */
-  protected $term1;
-
-  /**
-   * Stores the second term used in the different tests.
-   *
-   * @var \Drupal\taxonomy\TermInterface
-   */
-  protected $term2;
+class ViewsTaxonomyAutocompleteTest extends TaxonomyTestBase {
 
   /**
    * Modules to enable.
    *
    * @var array
    */
-  public static $modules = array('taxonomy');
+  public static $modules = array('views');
 
   public static function getInfo() {
     return array(
@@ -54,20 +32,6 @@ public static function getInfo() {
     );
   }
 
-  public function setUp() {
-    parent::setUp();
-
-    // Create the vocabulary for the tag field.
-    $this->vocabulary = entity_create('taxonomy_vocabulary',  array(
-      'name' => 'Views testing tags',
-      'vid' => 'views_testing_tags',
-    ));
-    $this->vocabulary->save();
-
-    $this->term1 = $this->createTerm('term');
-    $this->term2 = $this->createTerm('another');
-  }
-
   /**
    * Tests the views_ajax_autocomplete_taxonomy() AJAX callback.
    */
@@ -88,24 +52,4 @@ public function testTaxonomyAutocomplete() {
     $this->assertIdentical($expected, $this->drupalGetJSON($base_autocomplete_path, array('query' => array('q' => $partial))));
   }
 
-  /**
-   * Returns a new term with random properties.
-   *
-   * @param string $name
-   *   (optional) The name of the taxonomy term.
-   *
-   * @return \Drupal\taxonomy\Plugin\Core\Entity\Term
-   *   The created taxonomy term.
-   */
-  protected function createTerm($name = NULL) {
-    $term = entity_create('taxonomy_term', array(
-      'name' => $name ?: $this->randomName(),
-      'description' => $this->randomName(),
-      'vid' => $this->vocabulary->id(),
-      'langcode' => Language::LANGCODE_NOT_SPECIFIED,
-    ));
-    $term->save();
-    return $term;
-  }
-
 }
diff --git a/core/modules/views/lib/Drupal/views/ViewAccessController.php b/core/modules/views/lib/Drupal/views/ViewAccessController.php
deleted file mode 100644
index 7fee713..0000000
--- a/core/modules/views/lib/Drupal/views/ViewAccessController.php
+++ /dev/null
@@ -1,27 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\views\ViewAccessController.
- */
-
-namespace Drupal\views;
-
-use Drupal\Core\Entity\EntityAccessController;
-use Drupal\Core\Entity\EntityInterface;
-use Drupal\Core\Language\Language;
-use Drupal\Core\Session\AccountInterface;
-
-/**
- * Defines the access controller for the view entity type.
- */
-class ViewAccessController extends EntityAccessController {
-
-  /**
-   * {@inheritdoc}
-   */
-  public function access(EntityInterface $entity, $operation, $langcode = Language::LANGUAGE_DEFAULT, AccountInterface $account = NULL) {
-    return $operation == 'view' || user_access('administer views', $account);
-  }
-
-}
diff --git a/core/modules/views/views.api.php b/core/modules/views/views.api.php
index 3001caa..6b4245b 100644
--- a/core/modules/views/views.api.php
+++ b/core/modules/views/views.api.php
@@ -98,26 +98,6 @@
  */
 
 /**
- * Analyze a view to provide warnings about its configuration.
- *
- * @param \Drupal\views\ViewExecutable $view
- *   The view being executed.
- *
- * @return array
- *   Array of warning messages built by Analyzer::formatMessage to be displayed
- *   to the user following analysis of the view.
- */
-function hook_views_analyze(Drupal\views\ViewExecutable $view) {
-  $messages = array();
-
-  if ($view->display_handler->options['pager']['type'] == 'none') {
-    $messages[] = Drupal\views\Analyzer::formatMessage(t('This view has no pager. This could cause performance issues when the view contains many items.'), 'warning');
-  }
-
-  return $messages;
-}
-
-/**
  * Describe data tables (or the equivalent) to Views.
  *
  * The data described with this hook is fetched and retrieved by
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
index 53920b4..16f023c 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewAddFormController.php
@@ -28,18 +28,23 @@ class ViewAddFormController extends ViewFormControllerBase implements EntityCont
   /**
    * Constructs a new ViewEditFormController object.
    *
+   * @param string $operation
+   *   The name of the current operation.
    * @param \Drupal\views\Plugin\ViewsPluginManager $wizard_manager
    *   The wizard plugin manager.
    */
-  public function __construct(ViewsPluginManager $wizard_manager) {
+  public function __construct($operation, ViewsPluginManager $wizard_manager) {
+    parent::__construct($operation);
+
     $this->wizardManager = $wizard_manager;
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info, $operation = NULL) {
     return new static(
+      $operation,
       $container->get('plugin.manager.views.wizard')
     );
   }
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
index 04dd507..1f3869c 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewEditFormController.php
@@ -39,12 +39,16 @@ class ViewEditFormController extends ViewFormControllerBase implements EntityCon
   /**
    * Constructs a new ViewEditFormController object.
    *
+   * @param string $operation
+   *   The name of the current operation.
    * @param \Drupal\user\TempStoreFactory $temp_store_factory
    *   The factory for the temp store object.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    */
-  public function __construct(TempStoreFactory $temp_store_factory, Request $request) {
+  public function __construct($operation, TempStoreFactory $temp_store_factory, Request $request) {
+    parent::__construct($operation);
+
     $this->tempStore = $temp_store_factory->get('views');
     $this->request = $request;
   }
@@ -52,8 +56,9 @@ public function __construct(TempStoreFactory $temp_store_factory, Request $reque
   /**
    * {@inheritdoc}
    */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info, $operation = NULL) {
     return new static(
+      $operation,
       $container->get('user.tempstore'),
       $container->get('request')
     );
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php
index ad30ad1..429f953 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewListController.php
@@ -133,13 +133,13 @@ public function buildHeader() {
   }
 
   /**
-   * {@inheritdoc}
+   * Implements \Drupal\Core\Entity\EntityListController::getOperations().
    */
-  public function getOperations(EntityInterface $entity) {
-    $operations = parent::getOperations($entity);
-    $uri = $entity->uri();
+  public function getOperations(EntityInterface $view) {
+    $definition = parent::getOperations($view);
+    $uri = $view->uri();
 
-    $operations['clone'] = array(
+    $definition['clone'] = array(
       'title' => t('Clone'),
       'href' => $uri['path'] . '/clone',
       'options' => $uri['options'],
@@ -148,12 +148,12 @@ public function getOperations(EntityInterface $entity) {
 
     // Add AJAX functionality to enable/disable operations.
     foreach (array('enable', 'disable') as $op) {
-      if (isset($operations[$op])) {
-        $operations[$op]['ajax'] = TRUE;
+      if (isset($definition[$op])) {
+        $definition[$op]['ajax'] = TRUE;
       }
     }
 
-    return $operations;
+    return $definition;
   }
 
   /**
@@ -169,6 +169,10 @@ public function buildOperations(EntityInterface $entity) {
       }
     }
 
+    // Use the dropbutton #type.
+    unset($build['#theme']);
+    $build['#type'] = 'dropbutton';
+
     return $build;
   }
 
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
index 555ebac..b0efc08 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewPreviewFormController.php
@@ -26,18 +26,23 @@ class ViewPreviewFormController extends ViewFormControllerBase implements Entity
   /**
    * Constructs a new ViewPreviewFormController object.
    *
+   * @param string $operation
+   *   The name of the current operation.
    * @param \Drupal\user\TempStoreFactory $temp_store_factory
    *   The factory for the temp store object.
    */
-  public function __construct(TempStoreFactory $temp_store_factory) {
+  public function __construct($operation, TempStoreFactory $temp_store_factory) {
+    parent::__construct($operation);
+
     $this->tempStore = $temp_store_factory->get('views');
   }
 
   /**
    * {@inheritdoc}
    */
-  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info, $operation = NULL) {
     return new static(
+      $operation,
       $container->get('user.tempstore')
     );
   }
diff --git a/core/modules/views_ui/templates/views-ui-view-preview-section.html.twig b/core/modules/views_ui/templates/views-ui-view-preview-section.html.twig
deleted file mode 100644
index cfc840f..0000000
--- a/core/modules/views_ui/templates/views-ui-view-preview-section.html.twig
+++ /dev/null
@@ -1,20 +0,0 @@
-{#
-/**
- * @file
- * Default theme implementation for a views UI preview section.
- *
- * Available variables:
- * - title: The human readable section title.
- * - links: A list of contextual links.
- * - content: The content for this section preview.
- *
- * @see template_preprocess_views_ui_view_preview_section()
- *
- * @ingroup themeable
- */
-#}
-<h1 class="section-title">{{ title }}</h1>
-{% if links %}
-  <div class="contextual">{{ links }}</div>
-{% endif %}
-<div class="preview-section">{{ content }}</div>
diff --git a/core/modules/views_ui/views_ui.module b/core/modules/views_ui/views_ui.module
index 4ce0595..269bdcd 100644
--- a/core/modules/views_ui/views_ui.module
+++ b/core/modules/views_ui/views_ui.module
@@ -176,7 +176,6 @@ function views_ui_theme() {
     'views_ui_view_preview_section' => array(
       'variables' => array('view' => NULL, 'section' => NULL, 'content' => NULL, 'links' => ''),
       'file' => 'views_ui.theme.inc',
-      'template' => 'views-ui-view-preview-section',
     ),
 
     // Generic container wrapper, to use instead of theme_container when an id
diff --git a/core/modules/views_ui/views_ui.theme.inc b/core/modules/views_ui/views_ui.theme.inc
index 3a9aab3..8e503fc 100644
--- a/core/modules/views_ui/views_ui.theme.inc
+++ b/core/modules/views_ui/views_ui.theme.inc
@@ -389,14 +389,7 @@ function theme_views_ui_style_plugin_table($variables) {
 }
 
 /**
- * Prepares variables for views UI view preview section templates.
- *
- * Default template: views-ui-view-preview-section.html.twig.
- *
- * @param array $variables
- *   An associative array containing:
- *   - view: The view object.
- *   - section: The section name of a View (e.g. title, rows or pager).
+ * Theme preprocess for theme_views_ui_view_preview_section().
  */
 function template_preprocess_views_ui_view_preview_section(&$vars) {
   switch ($vars['section']) {
@@ -446,6 +439,8 @@ function template_preprocess_views_ui_view_preview_section(&$vars) {
 
   if (isset($links)) {
     $build = array(
+      '#prefix' => '<div class="contextual">',
+      '#suffix' => '</div>',
       '#theme' => 'links__contextual',
       '#links' => $links,
       '#attributes' => array('class' => array('contextual-links')),
@@ -453,7 +448,16 @@ function template_preprocess_views_ui_view_preview_section(&$vars) {
         'library' => array(array('contextual', 'drupal.contextual-links')),
       ),
     );
-    $vars['links'] = $build;
+    $vars['links'] = drupal_render($build);
   }
   $vars['theme_hook_suggestions'][] = 'views_ui_view_preview_section__' . $vars['section'];
 }
+
+/**
+ * Returns the HTML for a section of a View being previewed within the Views UI.
+ */
+function theme_views_ui_view_preview_section($vars) {
+  return '<h1 class="section-title">' . $vars['title'] . '</h1>'
+  . $vars['links']
+  . '<div class="preview-section">'. drupal_render($vars['content']) . '</div>';
+}
diff --git a/core/profiles/standard/config/field.field.field_image.yml b/core/profiles/standard/config/field.field.field_image.yml
index 0fc032a..42204e4 100644
--- a/core/profiles/standard/config/field.field.field_image.yml
+++ b/core/profiles/standard/config/field.field.field_image.yml
@@ -9,7 +9,7 @@ settings:
     file:
       label: File
       columns:
-        - target_id
+        - fid
         - width
         - height
     alt:
@@ -28,7 +28,7 @@ cardinality: '1'
 translatable: '0'
 entity_types: {  }
 indexes:
-  target_id:
-    - target_id
+  fid:
+    - fid
 status: 1
 langcode: und
diff --git a/core/profiles/standard/config/node.type.article.yml b/core/profiles/standard/config/node.type.article.yml
deleted file mode 100644
index dd2394f..0000000
--- a/core/profiles/standard/config/node.type.article.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-type: article
-uuid: 38fcdfbf-92a0-43d3-af30-8395cba668d4
-name: Article
-description: 'Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.'
-help: ''
-has_title: '1'
-title_label: Title
-settings:
-  node:
-    preview: '1'
-    options:
-      status: status
-      promote: promote
-      sticky: '0'
-      revision: '0'
-    submitted: '1'
-status: '1'
-langcode: en
diff --git a/core/profiles/standard/config/node.type.page.yml b/core/profiles/standard/config/node.type.page.yml
deleted file mode 100644
index 48a919a..0000000
--- a/core/profiles/standard/config/node.type.page.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-type: page
-uuid: f77b56af-2b34-4a2f-b7e9-2dcadfdc80d0
-name: 'Basic page'
-description: 'Use <em>basic pages</em> for your static content, such as an ''About us'' page.'
-help: ''
-has_title: '1'
-title_label: Title
-settings:
-  node:
-    preview: '1'
-    options:
-      status: status
-      promote: '0'
-      sticky: '0'
-      revision: '0'
-    submitted: '0'
-status: '1'
-langcode: en
diff --git a/core/profiles/standard/config/rdf.mapping.comment.comment_node_article.yml b/core/profiles/standard/config/rdf.mapping.comment.comment_node_article.yml
index 487fe5d..3a7ecaa 100644
--- a/core/profiles/standard/config/rdf.mapping.comment.comment_node_article.yml
+++ b/core/profiles/standard/config/rdf.mapping.comment.comment_node_article.yml
@@ -2,34 +2,23 @@ id: comment.comment_node_article
 targetEntityType: comment
 bundle: comment_node_article
 types:
-  - 'sioc:Post'
-  - 'sioct:Comment'
+  - 'schema:Comment'
 fieldMappings:
-  title:
+  subject:
     properties:
-      - 'dc:title'
+      - 'schema:name'
   created:
     properties:
-      - 'dc:date'
-      - 'dc:created'
-    datatype: 'xsd:dateTime'
+      - 'schema:dateCreated'
     datatype_callback: 'date_iso8601'
   changed:
     properties:
-      - 'dc:modified'
-    datatype: 'xsd:dateTime'
+      - 'schema:dateModified'
     datatype_callback: 'date_iso8601'
   comment_body:
     properties:
-      - 'content:encoded'
+      - 'schema:text'
   uid:
     properties:
-      - 'sioc:has_creator'
-    mapping_type: 'rel'
-  name:
-    properties:
-      - 'foaf:name'
-  pid:
-    properties:
-      - 'sioc:reply_of'
+      - 'schema:author'
     mapping_type: 'rel'
diff --git a/core/profiles/standard/config/rdf.mapping.node.article.yml b/core/profiles/standard/config/rdf.mapping.node.article.yml
index ac31562..b5413de 100644
--- a/core/profiles/standard/config/rdf.mapping.node.article.yml
+++ b/core/profiles/standard/config/rdf.mapping.node.article.yml
@@ -2,48 +2,35 @@ id: node.article
 targetEntityType: node
 bundle: article
 types:
-  - 'foaf:Document'
-  - 'sioc:Item'
+  - 'schema:Article'
 fieldMappings:
   title:
     properties:
-      - 'dc:title'
+      - 'schema:name'
   created:
     properties:
-      - 'dc:date'
-      - 'dc:created'
-    datatype: 'xsd:dateTime'
+      - 'schema:dateCreated'
     datatype_callback: 'date_iso8601'
   changed:
     properties:
-      - 'dc:modified'
-    datatype: 'xsd:dateTime'
+      - 'schema:dateModified'
     datatype_callback: 'date_iso8601'
   body:
     properties:
-      - 'content:encoded'
+      - 'schema:text'
   uid:
     properties:
-      - 'sioc:has_creator'
+      - 'schema:author'
     mapping_type: 'rel'
-  name:
-    properties:
-      - 'foaf:name'
   comment_count:
     properties:
-      - 'sioc:num_replies'
-    datatype: 'xsd:integer'
-  last_activity:
-    properties:
-      - 'sioc:last_activity_date'
-    datatype: 'xsd:dateTime'
-    datatype_callback: 'date_iso8601'
+      - 'schema:interactionCount'
+    datatype_callback: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
   field_image:
     properties:
-      - 'og:image'
-      - 'rdfs:seeAlso'
+      - 'schema:image'
     mapping_type: 'rel'
   field_tags:
     properties:
-      - 'dc:subject'
+      - 'schema:about'
     mapping_type: 'rel'
diff --git a/core/profiles/standard/config/rdf.mapping.node.page.yml b/core/profiles/standard/config/rdf.mapping.node.page.yml
index b21ff4c..91330c7 100644
--- a/core/profiles/standard/config/rdf.mapping.node.page.yml
+++ b/core/profiles/standard/config/rdf.mapping.node.page.yml
@@ -2,39 +2,27 @@ id: node.page
 targetEntityType: node
 bundle: page
 types:
-  - 'foaf:Document'
-  - 'sioc:Item'
+  - 'schema:WebPage'
 fieldMappings:
   title:
     properties:
-      - 'dc:title'
+      - 'schema:name'
   created:
     properties:
-      - 'dc:date'
-      - 'dc:created'
-    datatype: 'xsd:dateTime'
+      - 'schema:dateCreated'
     datatype_callback: 'date_iso8601'
   changed:
     properties:
-      - 'dc:modified'
-    datatype: 'xsd:dateTime'
+      - 'schema:dateModified'
     datatype_callback: 'date_iso8601'
   body:
     properties:
-      - 'content:encoded'
+      - 'schema:text'
   uid:
     properties:
-      - 'sioc:has_creator'
+      - 'schema:author'
     mapping_type: 'rel'
-  name:
-    properties:
-      - 'foaf:name'
   comment_count:
     properties:
-      - 'sioc:num_replies'
-    datatype: 'xsd:integer'
-  last_activity:
-    properties:
-      - 'sioc:last_activity_date'
-    datatype: 'xsd:dateTime'
-    datatype_callback: 'date_iso8601'
+      - 'schema:interactionCount'
+    datatype_callback: 'Drupal\rdf\SchemaOrgDataConverter::interactionCount'
diff --git a/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml b/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml
index 1e8c3da..051795c 100644
--- a/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml
+++ b/core/profiles/standard/config/rdf.mapping.taxonomy_term.tags.yml
@@ -2,9 +2,11 @@ id: taxonomy_term.tags
 targetEntityType: taxonomy_term
 bundle: tags
 types:
-  - 'skos:Concept'
+  - 'schema:Thing'
 fieldMappings:
   name:
     properties:
-      - 'rdfs:label'
-      - 'skos:prefLabel'
+      - 'schema:name'
+  description:
+    properties:
+      - 'schema:description'
diff --git a/core/profiles/standard/config/rdf.mapping.user.user.yml b/core/profiles/standard/config/rdf.mapping.user.user.yml
deleted file mode 100644
index aca7813..0000000
--- a/core/profiles/standard/config/rdf.mapping.user.user.yml
+++ /dev/null
@@ -1,13 +0,0 @@
-id: user.user
-targetEntityType: user
-bundle: user
-types:
-  - 'sioc:UserAccount'
-fieldMappings:
-  name:
-    properties:
-      - 'foaf:name'
-  homepage:
-    properties:
-      - 'foaf:page'
-    mapping_type: 'rel'
diff --git a/core/profiles/standard/standard.install b/core/profiles/standard/standard.install
index 5c29f4d..b465f35 100644
--- a/core/profiles/standard/standard.install
+++ b/core/profiles/standard/standard.install
@@ -24,9 +24,43 @@ function standard_install() {
   // Set front page to "node".
   config('system.site')->set('page.front', 'node')->save();
 
-  // Default "Basic page" to have comments disabled.
+  // Insert default pre-defined node types into the database. For a complete
+  // list of available node type attributes, refer to the node type API
+  // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
+  $types = array(
+    array(
+      'type' => 'page',
+      'name' => t('Basic page'),
+      'base' => 'node_content',
+      'description' => t("Use <em>basic pages</em> for your static content, such as an 'About us' page."),
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+    ),
+    array(
+      'type' => 'article',
+      'name' => t('Article'),
+      'base' => 'node_content',
+      'description' => t('Use <em>articles</em> for time-sensitive content like news, press releases or blog posts.'),
+      'custom' => 1,
+      'modified' => 1,
+      'locked' => 0,
+    ),
+  );
+
+  foreach ($types as $type) {
+    $type = node_type_set_defaults($type);
+    node_type_save($type);
+    node_add_body_field($type);
+  }
+
+  // Default "Basic page" to not be promoted and have comments disabled.
+  variable_set('node_options_page', array('status'));
   variable_set('comment_page', COMMENT_NODE_HIDDEN);
 
+  // Don't display date and author information for "Basic page" nodes by default.
+  variable_set('node_submitted_page', FALSE);
+
   // Allow visitor account creation with administrative approval.
   $user_settings = config('user.settings');
   $user_settings->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
