diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 7dc75f5..d0aec1e 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -20,6 +20,7 @@
 use Drupal\Core\Lock\DatabaseLockBackend;
 use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\Core\Entity\EntityBCDecorator;
 
 /**
  * @file
@@ -1843,14 +1844,13 @@ function drupal_set_title($title = NULL, $output = CHECK_PLAIN) {
  *   The user object.
  */
 function drupal_anonymous_user() {
-  $values = array(
+  return (object) array(
     'uid' => 0,
     'hostname' => Drupal::request()->getClientIP(),
     'roles' => array(
       DRUPAL_ANONYMOUS_RID => DRUPAL_ANONYMOUS_RID,
     ),
   );
-  return new User($values, 'user');
 }
 
 /**
diff --git a/core/includes/common.inc b/core/includes/common.inc
index eabc080..b737ea7 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -5601,7 +5601,7 @@ function drupal_render_cid_parts($granularity = NULL) {
     // resource drag for sites with many users, so when a module is being
     // equivocal, we favor the less expensive 'PER_ROLE' pattern.
     if ($granularity & DRUPAL_CACHE_PER_ROLE) {
-      $cid_parts[] = 'r.' . implode(',', array_keys($user->roles));
+      $cid_parts[] = 'r.' . implode(',', $user->roles);
     }
     elseif ($granularity & DRUPAL_CACHE_PER_USER) {
       $cid_parts[] = "u.$user->uid";
diff --git a/core/includes/entity.api.php b/core/includes/entity.api.php
index 148f11d..8add24c 100644
--- a/core/includes/entity.api.php
+++ b/core/includes/entity.api.php
@@ -548,7 +548,7 @@ function hook_entity_field_info_alter(&$info, $entity_type) {
  *   \Drupal\Core\TypedData\AccessibleInterface::access() for possible values.
  * @param \Drupal\Core\Entity\Field\Type\Field $field
  *   The entity field object on which the operation is to be performed.
- * @param \Drupal\user\Plugin\Core\Entity\User $account
+ * @param \Drupal\user\UserInterface $account
  *   The user account to check.
  *
  * @return bool|NULL
diff --git a/core/includes/session.inc b/core/includes/session.inc
index 17c73d7..c68c33c 100644
--- a/core/includes/session.inc
+++ b/core/includes/session.inc
@@ -108,9 +108,8 @@ function _drupal_session_read($sid) {
   // active user.
   if ($user && $user->uid > 0 && $user->status == 1) {
     // Add roles element to $user.
-    $user->roles = array();
-    $user->roles[DRUPAL_AUTHENTICATED_RID] = DRUPAL_AUTHENTICATED_RID;
-    $user->roles += db_query("SELECT ur.rid FROM {users_roles} ur WHERE ur.uid = :uid", array(':uid' => $user->uid))->fetchAllKeyed(0, 0);
+    $rids = db_query("SELECT ur.rid FROM {users_roles} ur WHERE ur.uid = :uid", array(':uid' => $user->uid))->fetchCol();
+    $user->roles = array_merge(array(DRUPAL_AUTHENTICATED_RID), $rids);
   }
   elseif ($user) {
     // The user is anonymous or blocked. Only preserve two fields from the
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index 6bb91e1..74cf0f9 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -166,6 +166,8 @@ public function resetCache(array $ids = NULL) {
     }
     else {
       $this->entityCache = array();
+      $this->entityFieldInfo = NULL;
+      $this->fieldDefinitions = array();
     }
   }
 
diff --git a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
index 9b7020a..45ae1e6 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageControllerNG.php
@@ -275,6 +275,12 @@ public function save(EntityInterface $entity) {
       // Ensure we are dealing with the actual entity.
       $entity = $entity->getNGEntity();
 
+      // There are some cases that pre-set ->original for performance. Make sure
+      // original is not a BC decorator.
+      if ($entity->original instanceof \Drupal\Core\Entity\EntityBCDecorator) {
+        $entity->original = $entity->original->getNGEntity();
+      }
+
       // Sync the changes made in the fields array to the internal values array.
       $entity->updateOriginalValues();
 
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index d48d0b7..e1abc47 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -10,6 +10,7 @@
 use Drupal\Component\Uuid\Uuid;
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\user\UserInterface;
 use IteratorAggregate;
 
 /**
@@ -257,7 +258,7 @@ public function getIterator() {
   /**
    * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
    */
-  public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) {
+  public function access($operation = 'view', UserInterface $account = NULL) {
     return \Drupal::entityManager()
       ->getAccessController($this->entityType)
       ->access($this, $operation, LANGUAGE_DEFAULT, $account);
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php
index 9b75d53..e92afbe 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessController.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Entity;
 
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines a default implementation for entity access controllers.
@@ -24,7 +24,7 @@ class EntityAccessController implements EntityAccessControllerInterface {
   /**
    * {@inheritdoc}
    */
-  public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+  public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE_DEFAULT, UserInterface $account = NULL) {
 
     // @todo Remove this once we can rely on $account.
     if (!$account) {
@@ -72,14 +72,14 @@ public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The user for which to check access.
    *
    * @return bool|null
    *   TRUE if access was granted, FALSE if access was denied and NULL if access
    *   could not be determined.
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     return NULL;
   }
 
@@ -93,7 +93,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, U
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The user for which to check access.
    *
    * @return bool|null
@@ -101,7 +101,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, U
    *   is no record for the given user, operation, langcode and entity in the
    *   cache.
    */
-  protected function getCache(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function getCache(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     $uid = $account ? $account->id() : 0;
     $uuid = $entity->uuid();
 
@@ -121,13 +121,13 @@ protected function getCache(EntityInterface $entity, $operation, $langcode, User
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The user for which to check access.
    *
    * @return bool
    *   TRUE if access was granted, FALSE otherwise.
    */
-  protected function setCache($access, EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function setCache($access, EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     $uid = $account ? $account->id() : 0;
     $uuid = $entity->uuid();
 
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php
index ddf3dfd..5b595ca 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Entity;
 
 // @todo Don't depend on module level code.
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines a common interface for entity access controller classes.
@@ -26,14 +26,14 @@
    * @param string $langcode
    *   (optional) The language code for which to check access. Defaults to
    *   LANGUAGE_DEFAULT.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   (optional) The user for which to check access, or NULL to check access
    *   for the current user. Defaults to NULL.
    *
    * @return bool
    *   TRUE if access was granted, FALSE otherwise.
    */
-  public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE_DEFAULT, User $account = NULL);
+  public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE_DEFAULT, UserInterface $account = NULL);
 
   /**
    * Clears all cached access checks.
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index 9697648..590fe5d 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -10,6 +10,7 @@
 use IteratorAggregate;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
+use Drupal\user\UserInterface;
 
 /**
  * Provides backwards compatible (BC) access to entity fields.
@@ -211,7 +212,7 @@ function __clone() {
   /**
    * Forwards the call to the decorated entity.
    */
-  public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) {
+  public function access($operation = 'view', UserInterface $account = NULL) {
     return $this->decorated->access($operation, $account);
   }
 
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
index 4dc7657..2cc58f4 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
@@ -10,6 +10,7 @@
 use Drupal\Core\TypedData\AccessibleInterface;
 use Drupal\Core\TypedData\ComplexDataInterface;
 use Drupal\Core\TypedData\TypedData;
+use Drupal\user\UserInterface;
 use ArrayIterator;
 use Drupal\Core\TypedData\TypedDataInterface;
 use IteratorAggregate;
@@ -210,7 +211,7 @@ public function onChange($property_name) {
   /**
    * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
    */
-  public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL) {
+  public function access($operation = 'view', UserInterface $account = NULL) {
     // Determine the language code of this translation by cutting of the
     // leading "@" from the property name to get the langcode.
     // @todo Add a way to set and get the langcode so that's more obvious what
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
index 4829bb7..ab861d1 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
@@ -8,7 +8,7 @@
 namespace Drupal\Core\Entity\Field\Type;
 
 use Drupal\Core\Entity\Field\FieldInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 use Drupal\Core\TypedData\TypedDataInterface;
 use Drupal\Core\TypedData\ItemList;
 
@@ -145,7 +145,7 @@ public function __unset($property_name) {
   /**
    * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
    */
-  public function access($operation = 'view', User $account = NULL) {
+  public function access($operation = 'view', UserInterface $account = NULL) {
     global $user;
     if (!isset($account) && $user->uid) {
       $account = user_load($user->uid);
@@ -190,7 +190,7 @@ public function access($operation = 'view', User $account = NULL) {
    * @return bool
    *   TRUE if access to this field is allowed per default, FALSE otherwise.
    */
-  public function defaultAccess($operation = 'view', User $account = NULL) {
+  public function defaultAccess($operation = 'view', UserInterface $account = NULL) {
     // Grant access per default.
     return TRUE;
   }
diff --git a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
index 1b0dacd..a268573 100644
--- a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
+++ b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\TypedData;
 
+use Drupal\user\UserInterface;
+
 /**
  * Interface for checking access.
  */
@@ -22,7 +24,7 @@
    *   - update
    *   - delete
    *   Defaults to 'view'.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   (optional) The user for which to check access, or NULL to check access
    *   for the current user. Defaults to NULL.
    *
@@ -32,6 +34,6 @@
    *
    * @todo Don't depend on module level code.
    */
-  public function access($operation = 'view', \Drupal\user\Plugin\Core\Entity\User $account = NULL);
+  public function access($operation = 'view', UserInterface $account = NULL);
 
 }
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php
index 69aee17..c8cc35a 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockAccessController.php
@@ -8,7 +8,7 @@
 namespace Drupal\custom_block;
 
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 use Drupal\Core\Entity\EntityAccessController;
 
 /**
@@ -19,7 +19,7 @@ class CustomBlockAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     if ($operation === 'view') {
       return TRUE;
     }
diff --git a/core/modules/block/lib/Drupal/block/BlockAccessController.php b/core/modules/block/lib/Drupal/block/BlockAccessController.php
index 693fb32..ec6b417 100644
--- a/core/modules/block/lib/Drupal/block/BlockAccessController.php
+++ b/core/modules/block/lib/Drupal/block/BlockAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityAccessController;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Provides a Block access controller.
@@ -19,7 +19,7 @@ class BlockAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     // Currently, only view access is implemented.
     if ($operation != 'view') {
       return FALSE;
@@ -43,7 +43,7 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, U
     // For blocks with roles associated, if none of the user's roles matches
     // the settings from this block, access is denied.
     $visibility = $entity->get('visibility');
-    if (!empty($visibility['role']['roles']) && !array_intersect(array_filter($visibility['role']['roles']), array_keys($user->roles))) {
+    if (!empty($visibility['role']['roles']) && !array_intersect(array_filter($visibility['role']['roles']), $user->roles)) {
       // No match.
       return FALSE;
     }
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 0c2cd55..bc12233 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1549,7 +1549,7 @@ function comment_prepare_author(Comment $comment) {
   if (!$account) {
     $account = entity_create('user', array('uid' => 0, 'name' => $comment->name->value, 'homepage' => $comment->homepage->value));
   }
-  return $account;
+  return $account->getBCEntity();
 }
 
 /**
diff --git a/core/modules/comment/comment.tokens.inc b/core/modules/comment/comment.tokens.inc
index d938c27..213f352 100644
--- a/core/modules/comment/comment.tokens.inc
+++ b/core/modules/comment/comment.tokens.inc
@@ -218,7 +218,7 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
     }
 
     if (($author_tokens = $token_service->findwithPrefix($tokens, 'author')) && $account = $comment->uid->entity) {
-      $replacements += $token_service->generate('user', $author_tokens, array('user' => $account), $options);
+      $replacements += $token_service->generate('user', $author_tokens, array('user' => $account->getBCEntity()), $options);
     }
   }
   elseif ($type == 'node' & !empty($data['node'])) {
diff --git a/core/modules/comment/lib/Drupal/comment/CommentAccessController.php b/core/modules/comment/lib/Drupal/comment/CommentAccessController.php
index b20d850..1b06b07 100644
--- a/core/modules/comment/lib/Drupal/comment/CommentAccessController.php
+++ b/core/modules/comment/lib/Drupal/comment/CommentAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityAccessController;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Access controller for the comment entity.
@@ -21,7 +21,7 @@ class CommentAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     switch ($operation) {
       case 'view':
         return user_access('access comments', $account);
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index 5585650..743f6d0 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
@@ -50,7 +50,8 @@ function testCommentLinks() {
 
     // Remove additional user permissions from $this->web_user added by setUp(),
     // since this test is limited to anonymous and authenticated roles only.
-    entity_delete_multiple('user_role', array(key($this->web_user->roles)));
+    $roles = $this->web_user->roles;
+    entity_delete_multiple('user_role', array(reset($roles)));
 
     // Matrix of possible environmental conditions and configuration settings.
     // See setEnvironment() for details.
diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
index 6f73d96..e4c675d 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
@@ -8,7 +8,7 @@
 namespace Drupal\contact;
 
 use Drupal\Core\Entity\EntityFormController;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Form controller for contact message forms.
@@ -63,7 +63,7 @@ public function form(array $form, array &$form_state) {
 
     // The user contact form only has a recipient, not a category.
     // @todo Convert user contact form into a locked contact category.
-    if ($message->recipient instanceof User) {
+    if ($message->recipient instanceof UserInterface) {
       $form['recipient'] = array(
         '#type' => 'item',
         '#title' => t('To'),
@@ -167,7 +167,7 @@ public function save(array $form, array &$form_state) {
       $to = implode(', ', $category->recipients);
       $recipient_langcode = language_default()->langcode;
     }
-    elseif ($message->recipient instanceof User) {
+    elseif ($message->recipient instanceof UserInterface) {
       // Send to the user in the user's preferred language.
       $to = $message->recipient->mail;
       $recipient_langcode = user_preferred_langcode($message->recipient);
@@ -211,7 +211,7 @@ public function save(array $form, array &$form_state) {
 
     // To avoid false error messages caused by flood control, redirect away from
     // the contact form; either to the contacted user account or the front page.
-    if ($message->recipient instanceof User && user_access('access user profiles')) {
+    if ($message->recipient instanceof UserInterface && user_access('access user profiles')) {
       $uri = $message->recipient->uri();
       $form_state['redirect'] = array($uri['path'], $uri['options']);
     }
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index 59d068b..4e7253e 100644
--- a/core/modules/file/file.field.inc
+++ b/core/modules/file/file.field.inc
@@ -249,7 +249,7 @@ function file_field_update(EntityInterface $entity, $field, $instance, $langcode
   }
 
   // Compare the original field values with the ones that are being saved.
-  $original = $entity->original;
+  $original = $entity->original->getBCEntity();
   $original_fids = array();
   if (!empty($original->{$field['field_name']}[$langcode])) {
     foreach ($original->{$field['field_name']}[$langcode] as $original_item) {
diff --git a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
index 4991892..8f34290 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
@@ -239,7 +239,7 @@ function testPrivateFileComment() {
     $user = $this->drupalCreateUser(array('access comments'));
 
     // Grant the admin user required comment permissions.
-    user_role_grant_permissions(key($this->admin_user->roles), array('administer comment fields'));
+    user_role_grant_permissions($this->admin_user->roles[1], array('administer comment fields'));
 
     // Revoke access comments permission from anon user, grant post to
     // authenticated.
diff --git a/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php b/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php
index 8667a5b..11eb3e5 100644
--- a/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php
+++ b/core/modules/filter/lib/Drupal/filter/Tests/FilterFormatAccessTest.php
@@ -176,9 +176,7 @@ function testFormatPermissions() {
    */
   function testFormatRoles() {
     // Get the role ID assigned to the regular user.
-    $roles = $this->web_user->roles;
-    unset($roles[DRUPAL_AUTHENTICATED_RID]);
-    $rid = key($roles);
+    $rid = $this->web_user->roles[0];
 
     // Check that this role appears in the list of roles that have access to an
     // allowed text format, but does not appear in the list of roles that have
diff --git a/core/modules/locale/lib/Drupal/locale/LocaleLookup.php b/core/modules/locale/lib/Drupal/locale/LocaleLookup.php
index cc515b4..7f7d272 100644
--- a/core/modules/locale/lib/Drupal/locale/LocaleLookup.php
+++ b/core/modules/locale/lib/Drupal/locale/LocaleLookup.php
@@ -46,7 +46,7 @@ public function __construct($langcode, $context, $stringStorage) {
     // Add the current user's role IDs to the cache key, this ensures that, for
     // example, strings for admin menu items and settings forms are not cached
     // for anonymous users.
-    $rids = implode(':', array_keys($GLOBALS['user']->roles));
+    $rids = implode(':', $GLOBALS['user']->roles);
     parent::__construct("locale:$langcode:$context:$rids", 'cache', array('locale' => TRUE));
   }
 
diff --git a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
index ee2b0c3..5dc6330 100644
--- a/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
+++ b/core/modules/locale/lib/Drupal/locale/Tests/LocaleUninstallTest.php
@@ -62,6 +62,12 @@ function testUninstallProcess() {
     $language_manager->init();
     // Check the UI language.
 
+    // @todo: If the global user is an EntityBCDecorator, getting the roles
+    // from it within LocaleLookup results in a loop that invokes LocaleLookup
+    // again.
+    global $user;
+    $user = drupal_anonymous_user();
+
     $this->assertEqual(language(LANGUAGE_TYPE_INTERFACE)->langcode, $this->langcode, t('Current language: %lang', array('%lang' => language(LANGUAGE_TYPE_INTERFACE)->langcode)));
 
     // Enable multilingual workflow option for articles.
diff --git a/core/modules/node/lib/Drupal/node/NodeAccessController.php b/core/modules/node/lib/Drupal/node/NodeAccessController.php
index cee9228..34f4b63 100644
--- a/core/modules/node/lib/Drupal/node/NodeAccessController.php
+++ b/core/modules/node/lib/Drupal/node/NodeAccessController.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\node;
 
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 use Drupal\Core\Entity\EntityAccessController;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityNG;
@@ -20,7 +20,7 @@ class NodeAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+  public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE_DEFAULT, UserInterface $account = NULL) {
     if (user_access('bypass node access', $account)) {
       return TRUE;
     }
@@ -33,7 +33,7 @@ public function access(EntityInterface $entity, $operation, $langcode = LANGUAGE
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $node, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $node, $operation, $langcode, UserInterface $account) {
     // Fetch information from the node object if possible.
     $status = isset($node->status) ? $node->status : NULL;
     $uid = isset($node->uid) ? $node->uid : NULL;
@@ -74,7 +74,7 @@ protected function checkAccess(EntityInterface $node, $operation, $langcode, Use
    *   'delete'.
    * @param string $langcode
    *   The language code for which to check access.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The user for which to check access.
    *
    * @return bool|null
@@ -82,7 +82,7 @@ protected function checkAccess(EntityInterface $node, $operation, $langcode, Use
    *   module implements hook_node_grants(), the node does not (yet) have an id
    *   or none of the implementing modules explicitly granted or denied access.
    */
-  protected function accessGrants(EntityInterface $node, $operation, $langcode, User $account) {
+  protected function accessGrants(EntityInterface $node, $operation, $langcode, UserInterface $account) {
     // If no module implements the hook or the node does not have an id there is
     // no point in querying the database for access grants.
     if (!module_implements('node_grants') || !$node->id()) {
@@ -110,7 +110,7 @@ protected function accessGrants(EntityInterface $node, $operation, $langcode, Us
     $query->range(0, 1);
 
     $grants = db_or();
-    foreach (node_access_grants($operation, $account) as $realm => $gids) {
+    foreach (node_access_grants($operation, $account instanceof User ? $account->getBCEntity() : $account) as $realm => $gids) {
       foreach ($gids as $gid) {
         $grants->condition(db_and()
           ->condition('gid', $gid)
diff --git a/core/modules/node/lib/Drupal/node/Tests/NodeTestBase.php b/core/modules/node/lib/Drupal/node/Tests/NodeTestBase.php
index 957e4ee..02a16da 100644
--- a/core/modules/node/lib/Drupal/node/Tests/NodeTestBase.php
+++ b/core/modules/node/lib/Drupal/node/Tests/NodeTestBase.php
@@ -41,7 +41,7 @@ function setUp() {
    *   operation should be granted.
    * @param \Drupal\node\Plugin\Core\Entity\Node $node
    *   The node object to check.
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The user account for which to check access.
    * @param string|null $langcode
    *   (optional) The language code indicating which translation of the node
diff --git a/core/modules/node/node.api.php b/core/modules/node/node.api.php
index 78a3139..8a17409 100644
--- a/core/modules/node/node.api.php
+++ b/core/modules/node/node.api.php
@@ -393,8 +393,8 @@ function hook_node_grants_alter(&$grants, $account, $op) {
 
   if ($op != 'view' && !empty($restricted)) {
     // Now check the roles for this account against the restrictions.
-    foreach ($restricted as $role_id) {
-      if (isset($account->roles[$role_id])) {
+    foreach ($account->roles as $rid) {
+      if (in_array($rid, $restricted)) {
         $grants = array();
       }
     }
diff --git a/core/modules/node/node.module b/core/modules/node/node.module
index 5c934df..31c6345 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -19,7 +19,7 @@
 use Drupal\Core\Template\Attribute;
 use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
 use Drupal\file\Plugin\Core\Entity\File;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Denotes that the node is not published.
@@ -2518,7 +2518,7 @@ function node_access($op, $node, $account = NULL, $langcode = NULL) {
 
   // Make sure that if an account is passed, that it is a fully loaded user
   // object.
-  if ($account && !($account instanceof User)) {
+  if ($account && !($account instanceof UserInterface)) {
     $account = user_load($account->uid);
   }
 
diff --git a/core/modules/overlay/overlay.module b/core/modules/overlay/overlay.module
index 1566740..8c5d11f 100644
--- a/core/modules/overlay/overlay.module
+++ b/core/modules/overlay/overlay.module
@@ -8,7 +8,7 @@
 use Symfony\Component\HttpFoundation\Response;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
 use Drupal\block\Plugin\Core\Entity\Block;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Implements hook_help().
@@ -455,7 +455,7 @@ function theme_overlay_disable_message($variables) {
 /**
  * Implements hook_block_access().
  */
-function overlay_block_access(Block $block, $operation, User $account, $langcode) {
+function overlay_block_access(Block $block, $operation, UserInterface $account, $langcode) {
   // If we are limiting rendering to a subset of page regions, hide all blocks
   // which appear in regions not on that list. Note that overlay_page_alter()
   // does a more comprehensive job of preventing unwanted regions from being
diff --git a/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php b/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php
index 04d78a4..fbfe050 100644
--- a/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php
+++ b/core/modules/search/lib/Drupal/search/Tests/SearchCommentTest.php
@@ -125,9 +125,7 @@ function testSearchResultsComment() {
   function testSearchResultsCommentAccess() {
     $comment_body = 'Test comment body';
     $this->comment_subject = 'Test comment subject';
-    $this->admin_role = $this->admin_user->roles;
-    unset($this->admin_role[DRUPAL_AUTHENTICATED_RID]);
-    $this->admin_role = key($this->admin_role);
+    $this->admin_role = $this->admin_user->roles[0];
 
     // Create a node.
     variable_set('comment_preview_article', DRUPAL_OPTIONAL);
diff --git a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php
index 2a9c397..b42fe65 100644
--- a/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php
+++ b/core/modules/shortcut/lib/Drupal/shortcut/ShortcutAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityAccessController;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines the access controller for the shortcut entity type.
@@ -19,7 +19,7 @@ class ShortcutAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     switch ($operation) {
       case 'edit':
         if (user_access('administer shortcuts', $account)) {
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index af86db7..609d628 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -485,7 +485,7 @@ protected function drupalCreateUser(array $permissions = array(), $name = NULL)
     $edit['pass']   = user_password();
     $edit['status'] = 1;
     if ($rid) {
-      $edit['roles'] = array($rid => $rid);
+      $edit['roles'] = array($rid);
     }
 
     $account = entity_create('user', $edit);
@@ -617,7 +617,7 @@ protected function checkPermissions(array $permissions, $reset = FALSE) {
    *   $account->pass_raw = $pass_raw;
    * @endcode
    *
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   User object representing the user to log in.
    *
    * @see drupalCreateUser()
@@ -646,7 +646,7 @@ protected function drupalLogin($account) {
   /**
    * Returns whether a given user account is logged in.
    *
-   * @param \Drupal\user\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The user account object to check.
    */
   protected function drupalUserIsLoggedIn($account) {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
index c29e4f3..c1c7ea8 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Language\Language;
 use Drupal\Core\TypedData\AccessibleInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 use Drupal\Core\Entity\EntityAccessController;
 
 /**
@@ -45,7 +45,7 @@ function setUp() {
   /**
    * Asserts entity access correctly grants or denies access.
    */
-  function assertEntityAccess($ops, AccessibleInterface $object, User $account = NULL) {
+  function assertEntityAccess($ops, AccessibleInterface $object, UserInterface $account = NULL) {
     foreach ($ops as $op => $result) {
       $message = format_string("Entity access returns @result with operation '@op'.", array(
         '@result' => !isset($result) ? 'null' : ($result ? 'true' : 'false'),
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php
index 1a8947c..73de54f 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityApiTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\system\Tests\Entity;
 
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Tests the basic Entity API.
@@ -50,10 +50,10 @@ public function testCRUD() {
    *
    * @param string $entity_type
    *   The entity type to run the tests with.
-   * @param \Drupal\user\Plugin\Core\Entity\User $user1
+   * @param \Drupal\user\UserInterface $user1
    *   The user to run the tests with.
    */
-  protected function assertCRUD($entity_type, User $user1) {
+  protected function assertCRUD($entity_type, UserInterface $user1) {
     // Create some test entities.
     $entity = entity_create($entity_type, array('name' => 'test', 'user_id' => $user1->uid));
     $entity->save();
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 29e1462..df4f0f1 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityFieldTest.php
@@ -117,19 +117,19 @@ protected function assertReadWrite($entity_type) {
     $this->assertTrue($entity->user_id[0] instanceof FieldItemInterface, format_string('%entity_type: Field item implements interface', array('%entity_type' => $entity_type)));
 
     $this->assertEqual($this->entity_user->uid, $entity->user_id->target_id, format_string('%entity_type: User id can be read.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name->value, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
 
     // Change the assigned user by entity.
     $new_user = $this->createUser();
     $entity->user_id->entity = $new_user;
     $this->assertEqual($new_user->uid, $entity->user_id->target_id, format_string('%entity_type: Updated user id can be read.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($new_user->name, $entity->user_id->entity->name, format_string('%entity_type: Updated user name value can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($new_user->name, $entity->user_id->entity->name->value, format_string('%entity_type: Updated user name value can be read.', array('%entity_type' => $entity_type)));
 
     // Change the assigned user by id.
     $new_user = $this->createUser();
     $entity->user_id->target_id = $new_user->uid;
     $this->assertEqual($new_user->uid, $entity->user_id->target_id, format_string('%entity_type: Updated user id can be read.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($new_user->name, $entity->user_id->entity->name, format_string('%entity_type: Updated user name value can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($new_user->name, $entity->user_id->entity->name->value, format_string('%entity_type: Updated user name value can be read.', array('%entity_type' => $entity_type)));
 
     // Try unsetting a field.
     $entity->name->value = NULL;
@@ -217,7 +217,7 @@ protected function assertReadWrite($entity_type) {
     ));
     $this->assertEqual($this->entity_name, $entity->name->value, format_string('%entity_type: Name value can be read.', array('%entity_type' => $entity_type)));
     $this->assertEqual($this->entity_user->uid, $entity->user_id->target_id, format_string('%entity_type: User id can be read.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name->value, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
     $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, format_string('%entity_type: Text field can be read.', array('%entity_type' => $entity_type)));
 
     // Test copying field values.
@@ -328,7 +328,7 @@ protected function assertSave($entity_type) {
     $this->assertEqual(LANGUAGE_NOT_SPECIFIED, $entity->langcode->value, format_string('%entity_type: Language code can be read.', array('%entity_type' => $entity_type)));
     $this->assertEqual(language_load(LANGUAGE_NOT_SPECIFIED), $entity->langcode->language, format_string('%entity_type: Language object can be read.', array('%entity_type' => $entity_type)));
     $this->assertEqual($this->entity_user->uid, $entity->user_id->target_id, format_string('%entity_type: User id can be read.', array('%entity_type' => $entity_type)));
-    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
+    $this->assertEqual($this->entity_user->name, $entity->user_id->entity->name->value, format_string('%entity_type: User name can be read.', array('%entity_type' => $entity_type)));
     $this->assertEqual($this->entity_field_text, $entity->field_test_text->value, format_string('%entity_type: Text field can be read.', array('%entity_type' => $entity_type)));
   }
 
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
index 4da3b21..5e73dbc 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityUnitTestBase.php
@@ -51,7 +51,7 @@ protected function createUser($values = array(), $permissions = array()) {
       ));
       $role->save();
       user_role_grant_permissions($role->id(), $permissions);
-      $values['roles'][$role->id()] = $role->id();
+      $values['roles'][] = $role->id();
     }
 
     $account = entity_create('user', $values + array(
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/FieldAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/FieldAccessTest.php
index b00bfea..a5db46a 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/FieldAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/FieldAccessTest.php
@@ -70,12 +70,12 @@ function testFieldAccess() {
     $values = array('name' => 'test');
     $account = entity_create('user', $values);
 
-    $this->assertFalse($entity->field_test_text->access('view', $account), 'Access to the field was denied.');
+    $this->assertFalse($entity->field_test_text->access('view', $account->getNGEntity()), 'Access to the field was denied.');
 
     $entity->field_test_text = 'access alter value';
-    $this->assertFalse($entity->field_test_text->access('view', $account), 'Access to the field was denied.');
+    $this->assertFalse($entity->field_test_text->access('view', $account->getNGEntity()), 'Access to the field was denied.');
 
     $entity->field_test_text = 'standard value';
-    $this->assertTrue($entity->field_test_text->access('view', $account), 'Access to the field was granted.');
+    $this->assertTrue($entity->field_test_text->access('view', $account->getNGEntity()), 'Access to the field was granted.');
   }
 }
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 882ae96..5d5fb63 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -104,10 +104,10 @@ function testContext() {
     $this->assertEqual($user->label(), $plugin->getTitle());
 
     // Test the getContextDefinitions() method.
-    $this->assertIdentical($plugin->getContextDefinitions(), array('user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User')));
+    $this->assertIdentical($plugin->getContextDefinitions(), array('user' => array('class' => 'Drupal\user\UserInterface')));
 
     // Test the getContextDefinition() method for a valid context.
-    $this->assertEqual($plugin->getContextDefinition('user'), array('class' => 'Drupal\user\Plugin\Core\Entity\User'));
+    $this->assertEqual($plugin->getContextDefinition('user'), array('class' => 'Drupal\user\UserInterface'));
 
     // Test the getContextDefinition() method for an invalid context.
     try {
diff --git a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
index 7b8aa9a..57869c4 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/PluginTestBase.php
@@ -74,7 +74,7 @@ public function setUp() {
         'label' => 'User name',
         'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock',
         'context' => array(
-          'user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User')
+          'user' => array('class' => 'Drupal\user\\UserInterface')
         ),
       ),
       'string_context' => array(
@@ -88,7 +88,7 @@ public function setUp() {
         'label' => 'Complex context',
         'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock',
         'context' => array(
-          'user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User'),
+          'user' => array('class' => 'Drupal\user\\UserInterface'),
           'node' => array('class' => 'Drupal\Core\Entity\EntityBCDecorator'),
         ),
       ),
diff --git a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php
index f344afb..6f44942 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/FieldUIUpgradePathTest.php
@@ -63,7 +63,7 @@ function testFieldUIPermissions() {
        ),
     );
 
-    $role_permissions = user_role_permissions(array($this->normal_role_id => $this->normal_role_name, $this->admin_role_id => $this->admin_role_name));
+    $role_permissions = user_role_permissions(array($this->normal_role_id, $this->admin_role_id));
     foreach ($permissions as $old_permission => $new_permissions) {
       $this->assertFalse(isset($role_permissions[$this->normal_role_id][$old_permission]), format_string('%role_name does not have the old %permission permission', array('%role_name' => $this->normal_role_name, '%permission' => $old_permission)));
       $this->assertTrue(isset($role_permissions[$this->admin_role_id][$old_permission]), format_string('%role_name still has the old %permission permission', array('%role_name' => $this->admin_role_name, '%permission' => $old_permission)));
diff --git a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestAccessController.php b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestAccessController.php
index 9da187d..67c73fb 100644
--- a/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestAccessController.php
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityAccessController;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines the access controller for the test entity type.
@@ -19,7 +19,7 @@ class EntityTestAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     if ($operation === 'view') {
       if ($langcode != LANGUAGE_DEFAULT) {
         return user_access('view test entity translations', $account);
diff --git a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
index 157e583..a897160 100644
--- a/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
+++ b/core/modules/system/tests/modules/plugin_test/lib/Drupal/plugin_test/Plugin/MockBlockManager.php
@@ -72,7 +72,7 @@ public function __construct() {
       'label' => t('User name'),
       'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockUserNameBlock',
       'context' => array(
-        'user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User')
+        'user' => array('class' => 'Drupal\user\UserInterface')
       ),
     ));
 
@@ -90,7 +90,7 @@ public function __construct() {
       'label' => t('Complex context'),
       'class' => 'Drupal\plugin_test\Plugin\plugin_test\mock_block\MockComplexContextBlock',
       'context' => array(
-        'user' => array('class' => 'Drupal\user\Plugin\Core\Entity\User'),
+        'user' => array('class' => 'Drupal\user\UserInterface'),
         'node' => array('class' => 'Drupal\Core\Entity\EntityBCDecorator'),
       ),
     ));
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php
index bd1cff8..0d6dbd0 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/TermAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityAccessController;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines an access controller for the taxonomy term entity.
@@ -21,7 +21,7 @@ class TermAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     switch ($operation) {
       case 'view':
         return user_access('access content', $account);
diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php
index bd02c30..8f6e54f 100644
--- a/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php
+++ b/core/modules/taxonomy/lib/Drupal/taxonomy/VocabularyAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityAccessController;
 use Drupal\Core\Entity\EntityInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines an access controller for the vocabulary entity.
@@ -21,7 +21,7 @@ class VocabularyAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     return user_access('administer taxonomy', $account);
   }
 
diff --git a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
index e12553f..0b36b11 100644
--- a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
@@ -229,9 +229,7 @@ function _testTextfieldWidgetsFormatted($field_type, $widget_type) {
     $format = filter_format_load($edit['format']);
     $format_id = $format->format;
     $permission = filter_permission_name($format);
-    $roles = $this->web_user->roles;
-    unset($roles[DRUPAL_AUTHENTICATED_RID]);
-    $rid = key($roles);
+    $rid = $this->web_user->roles[0];
     user_role_grant_permissions($rid, array($permission));
     $this->drupalLogin($this->web_user);
 
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php
index 41600ac..b53ab33 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationSettingsTest.php
@@ -87,6 +87,7 @@ function testSettingsUI() {
       'settings[comment][comment_node_article][fields][comment_body]' => TRUE,
     );
     $this->assertSettings('comment', 'comment_node_article', TRUE, $edit);
+    field_info_cache_clear();
     $field = field_info_field('comment_body');
     $this->assertTrue($field['translatable'], 'Comment body is translatable.');
 
diff --git a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationWorkflowsTest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationWorkflowsTest.php
index 9957552..ed02f82 100644
--- a/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationWorkflowsTest.php
+++ b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationWorkflowsTest.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\translation_entity\Tests;
 
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Tests entity translation workflows.
@@ -107,13 +107,13 @@ function testWorkflows() {
   /**
    * Checks that workflows have the expected behaviors for the given user.
    *
-   * @param \Drupal\user\Plugin\Core\Entity\User $user
+   * @param \Drupal\user\UserInterface $user
    *   The user to test the workflow behavior against.
    * @param array $expected_status
    *   The an associative array with the operation name as key and the expected
    *   status as value.
    */
-  protected function assertWorkflows(User $user, $expected_status) {
+  protected function assertWorkflows(UserInterface $user, $expected_status) {
     $default_langcode = $this->langcodes[0];
     $languages = language_list();
     $args = array('@user_label' => $user->name);
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index 82bd66d..bad8479 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -289,7 +289,7 @@ function translation_entity_translate_access(EntityInterface $entity) {
  *   The entity whose translation overview should be displayed.
  * @param $langcode
  *   The language code of the translation to be displayed.
- * @param \Drupal\user\Plugin\Core\Entity\User $account
+ * @param \Drupal\user\UserInterface $account
  *   (optional) The account for which view access should be checked. Defaults to
  *   the current user.
  */
diff --git a/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
index 104763d..cb44b96 100644
--- a/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
+++ b/core/modules/user/lib/Drupal/user/Access/RoleAccessCheck.php
@@ -40,14 +40,14 @@ public function access(Route $route, Request $request) {
 
     $explode_and = array_filter(array_map('trim', explode('+', $rid_string)));
     if (count($explode_and) > 1) {
-      $diff = array_diff($explode_and, array_keys($account->roles));
+      $diff = array_diff($explode_and, $account->roles);
       if (empty($diff)) {
         return TRUE;
       }
     }
     else {
       $explode_or = array_filter(array_map('trim', explode(',', $rid_string)));
-      $intersection = array_intersect($explode_or, array_keys($account->roles));
+      $intersection = array_intersect($explode_or, $account->roles);
       if (!empty($intersection)) {
         return TRUE;
       }
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index ca8e638..c820f67 100644
--- a/core/modules/user/lib/Drupal/user/AccountFormController.php
+++ b/core/modules/user/lib/Drupal/user/AccountFormController.php
@@ -146,7 +146,7 @@ public function form(array $form, array &$form_state) {
     $form['account']['roles'] = array(
       '#type' => 'checkboxes',
       '#title' => t('Roles'),
-      '#default_value' => (!$register && isset($account->roles) ? array_keys($account->roles) : array()),
+      '#default_value' => (!$register ? $account->roles : array()),
       '#options' => $roles,
       '#access' => $roles && user_access('administer permissions'),
       DRUPAL_AUTHENTICATED_RID => $checkbox_authenticated,
@@ -225,6 +225,19 @@ public function form(array $form, array &$form_state) {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  public function buildEntity(array $form, array &$form_state) {
+    // Change the roles array to a list of enabled roles.
+    // @todo: Move this to an value callback on the form element.
+    if (empty($this->roles_filtered)) {
+      $form_state['values']['roles'] = array_keys(array_filter($form_state['values']['roles']));
+      $this->roles_filtered = TRUE;
+    }
+    return parent::buildEntity($form, $form_state);
+  }
+
+  /**
    * Overrides Drupal\Core\Entity\EntityFormController::submit().
    */
   public function validate(array $form, array &$form_state) {
diff --git a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
index 44c4562..5a92181 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/Core/Entity/User.php
@@ -7,9 +7,10 @@
 
 namespace Drupal\user\Plugin\Core\Entity;
 
-use Drupal\Core\Entity\Entity;
+use Drupal\Core\Entity\EntityNG;
 use Drupal\Core\Entity\Annotation\EntityType;
 use Drupal\Core\Annotation\Translation;
+use Drupal\user\UserBCDecorator;
 use Drupal\user\UserInterface;
 
 /**
@@ -42,7 +43,7 @@
  *   }
  * )
  */
-class User extends Entity implements UserInterface {
+class User extends EntityNG implements UserInterface {
 
   /**
    * The user ID.
@@ -63,7 +64,7 @@ class User extends Entity implements UserInterface {
    *
    * @var string
    */
-  public $name = '';
+  public $name;
 
   /**
    * The user's password (hashed).
@@ -77,7 +78,7 @@ class User extends Entity implements UserInterface {
    *
    * @var string
    */
-  public $mail = '';
+  public $mail;
 
   /**
    * The user's default theme.
@@ -113,7 +114,7 @@ class User extends Entity implements UserInterface {
    *
    * @var integer
    */
-  public $access = 0;
+  public $access;
 
   /**
    * The timestamp when the user last logged in. A value of 0 means the user has
@@ -121,14 +122,14 @@ class User extends Entity implements UserInterface {
    *
    * @var integer
    */
-  public $login = 0;
+  public $login;
 
   /**
    * Whether the user is active (1) or blocked (0).
    *
    * @var integer
    */
-  public $status = 1;
+  public $status;
 
   /**
    * The user's timezone.
@@ -142,40 +143,96 @@ class User extends Entity implements UserInterface {
    *
    * @var string
    */
-  public $langcode = LANGUAGE_NOT_SPECIFIED;
+  public $langcode;
 
   /**
    * The user's preferred langcode for receiving emails and viewing the site.
    *
    * @var string
    */
-  public $preferred_langcode = LANGUAGE_NOT_SPECIFIED;
+  public $preferred_langcode;
 
   /**
    * The user's preferred langcode for viewing administration pages.
    *
    * @var string
    */
-  public $preferred_admin_langcode = LANGUAGE_NOT_SPECIFIED;
+  public $preferred_admin_langcode;
 
   /**
    * The email address used for initial account creation.
    *
    * @var string
    */
-  public $init = '';
+  public $init;
 
   /**
    * The user's roles.
    *
    * @var array
    */
-  public $roles = array();
+  public $roles;
+
+    /**
+   * The plain data values of the contained properties.
+   *
+   * Define default values.
+   *
+   * @var array
+   */
+  protected $values = array(
+    'langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))),
+    'preferred_langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))),
+    'admin_preffered_langcode' => array(LANGUAGE_DEFAULT => array(0 => array('value' => LANGUAGE_NOT_SPECIFIED))),
+    'name' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))),
+    'mail' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))),
+    'init' => array(LANGUAGE_DEFAULT => array(0 => array('value' => ''))),
+    'access' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 0))),
+    'login' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 0))),
+    'status' => array(LANGUAGE_DEFAULT => array(0 => array('value' => 1))),
+  );
 
   /**
-   * Implements Drupal\Core\Entity\EntityInterface::id().
+   * {@inheritdoc}
    */
   public function id() {
-    return $this->uid;
+    return $this->get('uid')->value;
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function init() {
+    parent::init();
+    unset($this->access);
+    unset($this->created);
+    unset($this->init);
+    unset($this->login);
+    unset($this->mail);
+    unset($this->name);
+    unset($this->pass);
+    unset($this->preferred_admin_langcode);
+    unset($this->preferred_langcode);
+    unset($this->roles);
+    unset($this->signature);
+    unset($this->signature_format);
+    unset($this->status);
+    unset($this->theme);
+    unset($this->timezone);
+    unset($this->uid);
+    unset($this->uuid);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getBCEntity() {
+    if (!isset($this->bcEntity)) {
+      // Initialize field definitions so that we can pass them by reference.
+      $this->getPropertyDefinitions();
+      $this->bcEntity = new UserBCDecorator($this, $this->fieldDefinitions);
+    }
+    return $this->bcEntity;
+  }
+
 }
diff --git a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Name.php b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Name.php
index 8c5104c..6b48054 100644
--- a/core/modules/user/lib/Drupal/user/Plugin/views/filter/Name.php
+++ b/core/modules/user/lib/Drupal/user/Plugin/views/filter/Name.php
@@ -26,8 +26,8 @@ function value_form(&$form, &$form_state) {
     if ($this->value) {
       $result = entity_load_multiple_by_properties('user', array('uid' => $this->value));
       foreach ($result as $account) {
-        if ($account->uid) {
-          $values[] = $account->name;
+        if ($account->id()) {
+          $values[] = $account->name->value;
         }
         else {
           $values[] = 'Anonymous'; // Intentionally NOT translated.
@@ -130,8 +130,8 @@ function validate_user_strings(&$form, $values) {
 
     $result = entity_load_multiple_by_properties('user', array('name' => $args));
     foreach ($result as $account) {
-      unset($missing[strtolower($account->name)]);
-      $uids[] = $account->uid;
+      unset($missing[strtolower($account->name->value)]);
+      $uids[] = $account->id();
     }
 
     if ($missing) {
@@ -156,10 +156,10 @@ public function adminSummary() {
       $result = entity_load_multiple_by_properties('user', array('uid' => $this->value));
       foreach ($result as $account) {
         if ($account->uid) {
-          $this->value_options[$account->uid] = $account->name;
+          $this->value_options[$account->id()] = $account->label();
         }
         else {
-          $this->value_options[$account->uid] = 'Anonymous'; // Intentionally NOT translated.
+          $this->value_options[$account->id()] = 'Anonymous'; // Intentionally NOT translated.
         }
       }
     }
diff --git a/core/modules/user/lib/Drupal/user/RoleAccessController.php b/core/modules/user/lib/Drupal/user/RoleAccessController.php
index 3fe0100..64973df 100644
--- a/core/modules/user/lib/Drupal/user/RoleAccessController.php
+++ b/core/modules/user/lib/Drupal/user/RoleAccessController.php
@@ -19,7 +19,7 @@ class RoleAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     switch ($operation) {
       case 'delete':
         if ($entity->id() == DRUPAL_ANONYMOUS_RID || $entity->id() == DRUPAL_AUTHENTICATED_RID) {
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserAdminTest.php b/core/modules/user/lib/Drupal/user/Tests/UserAdminTest.php
index 3b83b52..0769fff 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserAdminTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserAdminTest.php
@@ -60,8 +60,8 @@ function testUserAdmin() {
 
     // Filter the users by role. Grab the system-generated role name for User C.
     $roles = $user_c->roles;
-    unset($roles[DRUPAL_AUTHENTICATED_RID]);
-    $edit['role'] = key($roles);
+    unset($roles[array_search(DRUPAL_AUTHENTICATED_RID, $roles)]);
+    $edit['role'] = reset($roles);
     $this->drupalPost('admin/people', $edit, t('Refine'));
 
     // Check if the correct users show up when filtered by role.
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserEntityCallbacksTest.php b/core/modules/user/lib/Drupal/user/Tests/UserEntityCallbacksTest.php
index 15894ad..a4bfd52 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserEntityCallbacksTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserEntityCallbacksTest.php
@@ -33,7 +33,7 @@ function setUp() {
     parent::setUp();
 
     $this->account = $this->drupalCreateUser();
-    $this->anonymous = drupal_anonymous_user();
+    $this->anonymous = entity_create('user', (array) drupal_anonymous_user());
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
index 2455b10..3fc3b4b 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
@@ -28,8 +28,8 @@ function setUp() {
 
     // Find the new role ID.
     $all_rids = $this->admin_user->roles;
-    unset($all_rids[DRUPAL_AUTHENTICATED_RID]);
-    $this->rid = key($all_rids);
+    unset($all_rids[array_search(DRUPAL_AUTHENTICATED_RID, $all_rids)]);
+    $this->rid = reset($all_rids);
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
index db649b0..dd4303c 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserRegistrationTest.php
@@ -45,7 +45,7 @@ function testRegistrationWithEmailVerification() {
     $this->assertText(t('A welcome message with further instructions has been sent to your e-mail address.'), 'User registered successfully.');
     $accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
     $new_user = reset($accounts);
-    $this->assertTrue($new_user->status, 'New account is active after registration.');
+    $this->assertTrue($new_user->status->value, 'New account is active after registration.');
 
     // Allow registration by site visitors, but require administrator approval.
     $config->set('register', USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL)->save();
@@ -56,7 +56,7 @@ function testRegistrationWithEmailVerification() {
     $this->container->get('plugin.manager.entity')->getStorageController('user')->resetCache();
     $accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
     $new_user = reset($accounts);
-    $this->assertFalse($new_user->status, 'New account is blocked until approved by an administrator.');
+    $this->assertFalse($new_user->status->value, 'New account is blocked until approved by an administrator.');
   }
 
   function testRegistrationWithoutEmailVerification() {
@@ -114,7 +114,7 @@ function testRegistrationWithoutEmailVerification() {
     $edit = array(
       'status' => 1,
     );
-    $this->drupalPost('user/' . $new_user->uid . '/edit', $edit, t('Save'));
+    $this->drupalPost('user/' . $new_user->id() . '/edit', $edit, t('Save'));
     $this->drupalLogout();
 
     // Login after administrator approval.
@@ -177,16 +177,16 @@ function testRegistrationDefaultValues() {
     // Check user fields.
     $accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
     $new_user = reset($accounts);
-    $this->assertEqual($new_user->name, $name, 'Username matches.');
-    $this->assertEqual($new_user->mail, $mail, 'E-mail address matches.');
-    $this->assertEqual($new_user->theme, '', 'Correct theme field.');
-    $this->assertEqual($new_user->signature, '', 'Correct signature field.');
-    $this->assertTrue(($new_user->created > REQUEST_TIME - 20 ), 'Correct creation time.');
-    $this->assertEqual($new_user->status, $config_user_settings->get('register') == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.');
-    $this->assertEqual($new_user->timezone, $config_system_timezone->get('default'), 'Correct time zone field.');
-    $this->assertEqual($new_user->langcode, language_default()->langcode, 'Correct language field.');
-    $this->assertEqual($new_user->preferred_langcode, language_default()->langcode, 'Correct preferred language field.');
-    $this->assertEqual($new_user->init, $mail, 'Correct init field.');
+    $this->assertEqual($new_user->name->value, $name, 'Username matches.');
+    $this->assertEqual($new_user->mail->value, $mail, 'E-mail address matches.');
+    $this->assertEqual($new_user->theme->value, '', 'Correct theme field.');
+    $this->assertEqual($new_user->signature->value, '', 'Correct signature field.');
+    $this->assertTrue(($new_user->created->value > REQUEST_TIME - 20 ), 'Correct creation time.');
+    $this->assertEqual($new_user->status->value, $config_user_settings->get('register') == USER_REGISTER_VISITORS ? 1 : 0, 'Correct status field.');
+    $this->assertEqual($new_user->timezone->value, $config_system_timezone->get('default'), 'Correct time zone field.');
+    $this->assertEqual($new_user->langcode->value, language_default()->langcode, 'Correct language field.');
+    $this->assertEqual($new_user->preferred_langcode->value, language_default()->langcode, 'Correct preferred language field.');
+    $this->assertEqual($new_user->init->value, $mail, 'Correct init field.');
   }
 
   /**
@@ -243,7 +243,7 @@ function testRegistrationWithUserFields() {
     // Check user fields.
     $accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
     $new_user = reset($accounts);
-    $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][0]['value'], $value, 'The field value was correclty saved.');
+    $this->assertEqual($new_user->test_user_field->value, $value, 'The field value was correclty saved.');
 
     // Check that the 'add more' button works.
     $field['cardinality'] = FIELD_CARDINALITY_UNLIMITED;
@@ -271,9 +271,9 @@ function testRegistrationWithUserFields() {
       // Check user fields.
       $accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail));
       $new_user = reset($accounts);
-      $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][0]['value'], $value, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
-      $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][1]['value'], $value + 1, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
-      $this->assertEqual($new_user->test_user_field[LANGUAGE_NOT_SPECIFIED][2]['value'], $value + 2, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
+      $this->assertEqual($new_user->test_user_field[0]->value, $value, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
+      $this->assertEqual($new_user->test_user_field[1]->value, $value + 1, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
+      $this->assertEqual($new_user->test_user_field[2]->value, $value + 2, format_string('@js : The field value was correclty saved.', array('@js' => $js)));
     }
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserRolesAssignmentTest.php b/core/modules/user/lib/Drupal/user/Tests/UserRolesAssignmentTest.php
index 349b2a9..e612374 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserRolesAssignmentTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserRolesAssignmentTest.php
@@ -94,10 +94,10 @@ function testCreateUserWithRole() {
   private function userLoadAndCheckRoleAssigned($account, $rid, $is_assigned = TRUE) {
     $account = user_load($account->uid, TRUE);
     if ($is_assigned) {
-      $this->assertTrue(array_key_exists($rid, $account->roles), 'The role is present in the user object.');
+      $this->assertTrue(array_search($rid, $account->roles), 'The role is present in the user object.');
     }
     else {
-      $this->assertFalse(array_key_exists($rid, $account->roles), 'The role is not present in the user object.');
+      $this->assertFalse(array_search($rid, $account->roles), 'The role is not present in the user object.');
     }
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php b/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php
index 171a976..fe3fa0f 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserTranslationUITest.php
@@ -39,6 +39,8 @@ function setUp() {
     $this->testLanguageSelector = FALSE;
     $this->name = $this->randomName();
     parent::setUp();
+
+    entity_get_controller('user')->resetCache();
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/AccessTestBase.php b/core/modules/user/lib/Drupal/user/Tests/Views/AccessTestBase.php
index 5455eaa..c1a26fc 100644
--- a/core/modules/user/lib/Drupal/user/Tests/Views/AccessTestBase.php
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/AccessTestBase.php
@@ -54,11 +54,11 @@ protected function setUp() {
 
     $this->adminUser = $this->drupalCreateUser(array('access all views'));
     $this->webUser = $this->drupalCreateUser();
-    $this->webRole = current($this->webUser->roles);
+    $this->webRole = $this->webUser->roles[0];
 
     $this->normalRole = $this->drupalCreateRole(array());
     $this->normalUser = $this->drupalCreateUser(array('views_test_data test permission'));
-    $this->normalUser->roles[$this->normalRole] = $this->normalRole;
+    $this->normalUser->getNGEntity()->roles[2] = $this->normalRole;
     // @todo when all the plugin information is cached make a reset function and
     // call it here.
   }
diff --git a/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldRoleTest.php b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldRoleTest.php
index 55ec424..7c70baa 100644
--- a/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldRoleTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/Views/HandlerFieldRoleTest.php
@@ -41,9 +41,9 @@ public function testRole() {
     $this->drupalCreateRole(array('access content'), $rolename_not_assigned, $rolename_not_assigned);
 
     // Add roles to user 1.
-    $user = user_load(1);
-    $user->roles[$rid_a] = $rolename_a;
-    $user->roles[$rid_b] = $rolename_b;
+    $user = entity_load('user', 1);
+    $user->roles[1]->value = $rolename_a;
+    $user->roles[2]->value = $rolename_b;
     $user->save();
 
     $view = views_get_view('test_views_handler_field_role');
diff --git a/core/modules/user/lib/Drupal/user/UserAccessController.php b/core/modules/user/lib/Drupal/user/UserAccessController.php
index 4332fbc..dd7f230 100644
--- a/core/modules/user/lib/Drupal/user/UserAccessController.php
+++ b/core/modules/user/lib/Drupal/user/UserAccessController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityAccessController;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Defines the access controller for the user entity type.
@@ -19,7 +19,7 @@ class UserAccessController extends EntityAccessController {
   /**
    * {@inheritdoc}
    */
-  protected function checkAccess(EntityInterface $entity, $operation, $langcode, User $account) {
+  protected function checkAccess(EntityInterface $entity, $operation, $langcode, UserInterface $account) {
     switch ($operation) {
       case 'view':
         return $this->viewAccess($entity, $langcode, $account);
@@ -32,14 +32,14 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, U
       case 'update':
         // Users can always edit their own account. Users with the 'administer
         // users' permission can edit any account except the anonymous account.
-        return (($account->uid == $entity->uid) || user_access('administer users', $account)) && $entity->uid > 0;
+        return (($account->uid == $entity->uid->value) || user_access('administer users', $account)) && $entity->uid->value > 0;
         break;
 
       case 'delete':
         // Users with 'cancel account' permission can cancel their own account,
         // users with 'administer users' permission can cancel any account
         // except the anonymous account.
-        return ((($account->uid == $entity->uid) && user_access('cancel account', $account)) || user_access('administer users', $account)) && $entity->uid > 0;
+        return ((($account->uid == $entity->uid->value) && user_access('cancel account', $account)) || user_access('administer users', $account)) && $entity->uid->value > 0;
         break;
     }
   }
@@ -49,16 +49,16 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, U
    *
    * See EntityAccessControllerInterface::view() for parameters.
    */
-  protected function viewAccess(EntityInterface $entity, $langcode, User $account) {
+  protected function viewAccess(EntityInterface $entity, $langcode, UserInterface $account) {
     // Never allow access to view the anonymous user account.
-    if ($entity->uid) {
+    if ($entity->uid->value) {
       // Admins can view all, users can view own profiles at all times.
-      if ($account->uid == $entity->uid || user_access('administer users', $account)) {
+      if ($account->uid == $entity->uid->value || user_access('administer users', $account)) {
         return TRUE;
       }
       elseif (user_access('access user profiles', $account)) {
         // Only allow view access if the account is active.
-        return $entity->status;
+        return $entity->status->value;
       }
     }
     return FALSE;
diff --git a/core/modules/user/lib/Drupal/user/UserBCDecorator.php b/core/modules/user/lib/Drupal/user/UserBCDecorator.php
new file mode 100644
index 0000000..586bc0a
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserBCDecorator.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\UserBCDecorator.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Entity\EntityBCDecorator;
+
+/**
+ * Defines the user specific entity BC decorator.
+ */
+class UserBCDecorator extends EntityBCDecorator implements UserInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function &__get($name) {
+    // Special handling for roles, as the return value is expected to be an
+    // array.
+    if ($name == 'roles') {
+      $roles = array();
+      foreach ($this->getNGEntity()->roles as $role) {
+        $roles[] = $role->value;
+      }
+      return $roles;
+    }
+    return parent::__get($name);
+  }
+}
diff --git a/core/modules/user/lib/Drupal/user/UserConfigContext.php b/core/modules/user/lib/Drupal/user/UserConfigContext.php
index 137b915..1d5f497 100644
--- a/core/modules/user/lib/Drupal/user/UserConfigContext.php
+++ b/core/modules/user/lib/Drupal/user/UserConfigContext.php
@@ -8,7 +8,7 @@
 namespace Drupal\user;
 
 use Drupal\Core\Config\Context\ConfigContext;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterfaceInterface;
 
 
 /**
@@ -29,13 +29,13 @@ class UserConfigContext extends ConfigContext {
   /**
    * Creates the configuration context for user accounts.
    *
-   * @param \Drupal\user\Plugin\Core\Entity\User $account
+   * @param \Drupal\user\UserInterface $account
    *   The account to add to the config context.
    *
    * @return \Drupal\user\UserConfigContext
    *   The user config context object.
    */
-  public function setAccount(User $account) {
+  public function setAccount(UserInterface $account) {
     $this->set(self::USER_KEY, $account);
     // Re-initialize since the user change changes the context fundamentally.
     $this->init();
diff --git a/core/modules/user/lib/Drupal/user/UserInterface.php b/core/modules/user/lib/Drupal/user/UserInterface.php
index 99818a8..3a98dd5 100644
--- a/core/modules/user/lib/Drupal/user/UserInterface.php
+++ b/core/modules/user/lib/Drupal/user/UserInterface.php
@@ -2,7 +2,7 @@
 
 /**
  * @file
- * Contains \Drupal\user\Plugin\Core\Entity\UserInterface.
+ * Contains \Drupal\user\UserInterface.
  */
 
 namespace Drupal\user;
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 3d8e981..b1debbc 100644
--- a/core/modules/user/lib/Drupal/user/UserStorageController.php
+++ b/core/modules/user/lib/Drupal/user/UserStorageController.php
@@ -9,7 +9,7 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityMalformedException;
-use Drupal\Core\Entity\DatabaseStorageController;
+use Drupal\Core\Entity\DatabaseStorageControllerNG;
 
 /**
  * Controller class for users.
@@ -17,7 +17,7 @@
  * This extends the Drupal\Core\Entity\DatabaseStorageController class, adding
  * required special handling for user objects.
  */
-class UserStorageController extends DatabaseStorageController {
+class UserStorageController extends DatabaseStorageControllerNG {
 
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::attachLoad().
@@ -26,17 +26,17 @@ function attachLoad(&$queried_users, $load_revision = FALSE) {
     foreach ($queried_users as $key => $record) {
       $queried_users[$key]->roles = array();
       if ($record->uid) {
-        $queried_users[$record->uid]->roles[DRUPAL_AUTHENTICATED_RID] = DRUPAL_AUTHENTICATED_RID;
+        $queried_users[$record->uid]->roles[] = DRUPAL_AUTHENTICATED_RID;
       }
       else {
-        $queried_users[$record->uid]->roles[DRUPAL_ANONYMOUS_RID] = DRUPAL_ANONYMOUS_RID;
+        $queried_users[$record->uid]->roles[] = DRUPAL_ANONYMOUS_RID;
       }
     }
 
     // Add any additional roles from the database.
     $result = db_query('SELECT rid, uid FROM {users_roles} WHERE uid IN (:uids)', array(':uids' => array_keys($queried_users)));
     foreach ($result as $record) {
-      $queried_users[$record->uid]->roles[$record->rid] = $record->rid;
+      $queried_users[$record->uid]->roles[] = $record->rid;
     }
 
     // Call the default attachLoad() method. This will add fields and call
@@ -52,17 +52,17 @@ public function create(array $values) {
       $values['created'] = REQUEST_TIME;
     }
     // Users always have the authenticated user role.
-    $values['roles'][DRUPAL_AUTHENTICATED_RID] = DRUPAL_AUTHENTICATED_RID;
+    $values['roles'][] = DRUPAL_AUTHENTICATED_RID;
 
-    return parent::create($values);
+    return parent::create($values)->getBCEntity();
   }
 
   /**
    * Overrides Drupal\Core\Entity\DatabaseStorageController::save().
    */
   public function save(EntityInterface $entity) {
-    if (empty($entity->uid)) {
-      $entity->uid = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
+    if (!$entity->uid->value) {
+      $entity->uid->value = db_next_id(db_query('SELECT MAX(uid) FROM {users}')->fetchField());
       $entity->enforceIsNew();
     }
     parent::save($entity);
@@ -73,11 +73,11 @@ public function save(EntityInterface $entity) {
    */
   protected function preSave(EntityInterface $entity) {
     // Update the user password if it has changed.
-    if ($entity->isNew() || (!empty($entity->pass) && $entity->pass != $entity->original->pass)) {
+    if ($entity->isNew() || ($entity->pass->value && $entity->pass->value != $entity->original->pass->value)) {
       // Allow alternate password hashing schemes.
-      $entity->pass = drupal_container()->get('password')->hash(trim($entity->pass));
+      $entity->pass->value = drupal_container()->get('password')->hash(trim($entity->pass->value));
       // Abort if the hashing failed and returned FALSE.
-      if (!$entity->pass) {
+      if (!$entity->pass->value) {
         throw new EntityMalformedException('The entity does not have a password.');
       }
     }
@@ -85,16 +85,11 @@ protected function preSave(EntityInterface $entity) {
     if (!$entity->isNew()) {
       // If the password is empty, that means it was not changed, so use the
       // original password.
-      if (empty($entity->pass)) {
-        $entity->pass = $entity->original->pass;
+      if (empty($entity->pass->value)) {
+        $entity->pass->value = $entity->original->pass->value;
       }
     }
 
-    // Prepare user roles.
-    if (isset($entity->roles)) {
-      $entity->roles = array_filter($entity->roles);
-    }
-
     // Store account cancellation information.
     foreach (array('user_cancel_method', 'user_cancel_notify') as $key) {
       if (isset($entity->{$key})) {
@@ -111,28 +106,25 @@ protected function postSave(EntityInterface $entity, $update) {
     if ($update) {
       // If the password has been changed, delete all open sessions for the
       // user and recreate the current one.
-      if ($entity->pass != $entity->original->pass) {
-        drupal_session_destroy_uid($entity->uid);
-        if ($entity->uid == $GLOBALS['user']->uid) {
+      if ($entity->pass->value != $entity->original->pass->value) {
+        drupal_session_destroy_uid($entity->id());
+        if ($entity->id() == $GLOBALS['user']->uid) {
           drupal_session_regenerate();
         }
       }
 
-      // Remove roles that are no longer enabled for the user.
-      $entity->roles = array_filter($entity->roles);
-
-      // Reload user roles if provided.
-      if ($entity->roles != $entity->original->roles) {
+      // Update user roles if changed.
+      if ($entity->roles->getValue() != $entity->original->roles->getValue()) {
         db_delete('users_roles')
-          ->condition('uid', $entity->uid)
+          ->condition('uid', $entity->id())
           ->execute();
 
         $query = db_insert('users_roles')->fields(array('uid', 'rid'));
-        foreach (array_keys($entity->roles) as $rid) {
-          if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+        foreach ($entity->roles as $role) {
+          if (!in_array($role->value, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
             $query->values(array(
-              'uid' => $entity->uid,
-              'rid' => $rid,
+              'uid' => $entity->id(),
+              'rid' => $role->value,
             ));
           }
         }
@@ -140,26 +132,26 @@ protected function postSave(EntityInterface $entity, $update) {
       }
 
       // If the user was blocked, delete the user's sessions to force a logout.
-      if ($entity->original->status != $entity->status && $entity->status == 0) {
-        drupal_session_destroy_uid($entity->uid);
+      if ($entity->original->status->value != $entity->status->value && $entity->status->value == 0) {
+        drupal_session_destroy_uid($entity->id());
       }
 
       // Send emails after we have the new user object.
-      if ($entity->status != $entity->original->status) {
+      if ($entity->status->value != $entity->original->status->value) {
         // The user's status is changing; conditionally send notification email.
-        $op = $entity->status == 1 ? 'status_activated' : 'status_blocked';
-        _user_mail_notify($op, $entity);
+        $op = $entity->status->value == 1 ? 'status_activated' : 'status_blocked';
+        _user_mail_notify($op, $entity->getBCEntity());
       }
     }
     else {
       // Save user roles.
       if (count($entity->roles) > 1) {
         $query = db_insert('users_roles')->fields(array('uid', 'rid'));
-        foreach (array_keys($entity->roles) as $rid) {
-          if (!in_array($rid, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
+        foreach ($entity->roles as $role) {
+          if (!in_array($role->value, array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID))) {
             $query->values(array(
-              'uid' => $entity->uid,
-              'rid' => $rid,
+              'uid' => $entity->id(),
+              'rid' => $role->value,
             ));
           }
         }
@@ -177,4 +169,123 @@ protected function postDelete($entities) {
       ->execute();
     drupal_container()->get('user.data')->delete(NULL, array_keys($entities));
   }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function invokeHook($hook, EntityInterface $entity) {
+    $function = 'field_attach_' . $hook;
+    // @todo: field_attach_delete_revision() is named the wrong way round,
+    // consider renaming it.
+    if ($function == 'field_attach_revision_delete') {
+      $function = 'field_attach_delete_revision';
+    }
+    if (!empty($this->entityInfo['fieldable']) && function_exists($function)) {
+      $function($entity->getBCEntity());
+    }
+
+    // Invoke the hook.
+    \Drupal::moduleHandler()->invokeAll($this->entityType . '_' . $hook, array($entity->getBCEntity()));
+    // Invoke the respective entity-level hook.
+    \Drupal::moduleHandler()->invokeAll('entity_' . $hook, array($entity->getBCEntity(), $this->entityType));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function baseFieldDefinitions() {
+    $properties['uid'] = array(
+      'label' => t('User ID'),
+      'description' => t('The user ID.'),
+      'type' => 'integer_field',
+      'read-only' => TRUE,
+    );
+    $properties['uuid'] = array(
+      'label' => t('UUID'),
+      'description' => t('The user UUID.'),
+      'type' => 'string_field',
+      'read-only' => TRUE,
+    );
+    $properties['langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t('The user language code.'),
+      'type' => 'language_field',
+    );
+    $properties['preferred_langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t("The user's preferred langcode for receiving emails and viewing the site."),
+      'type' => 'language_field',
+    );
+    $properties['preferred_admin_langcode'] = array(
+      'label' => t('Language code'),
+      'description' => t("The user's preferred langcode for viewing administration pages."),
+      'type' => 'language_field',
+    );
+    $properties['name'] = array(
+      'label' => t('Name'),
+      'description' => t('The name of this user'),
+      'type' => 'string_field',
+    );
+    $properties['pass'] = array(
+      'label' => t('Name'),
+      'description' => t('The password of this user (hashed)'),
+      'type' => 'string_field',
+    );
+    $properties['mail'] = array(
+      'label' => t('Name'),
+      'description' => t('The e-mail of this user'),
+      'type' => 'string_field',
+    );
+    $properties['signature'] = array(
+      'label' => t('Name'),
+      'description' => t('The signature of this user'),
+      'type' => 'string_field',
+    );
+    $properties['signature_format'] = array(
+      'label' => t('Name'),
+      'description' => t('The signature format of this user'),
+      'type' => 'string_field',
+    );
+    $properties['theme'] = array(
+      'label' => t('Theme'),
+      'description' => t('The default theme of this user'),
+      'type' => 'string_field',
+    );
+    $properties['timezone'] = array(
+      'label' => t('Timeone'),
+      'description' => t('The timezone of this user'),
+      'type' => 'string_field',
+    );
+    $properties['status'] = array(
+      'label' => t('User status'),
+      'description' => t('Whether the user is active (1) or blocked (0).'),
+      'type' => 'boolean_field',
+    );
+    $properties['created'] = array(
+      'label' => t('Created'),
+      'description' => t('The time that the node was created.'),
+      'type' => 'integer_field',
+    );
+    $properties['access'] = array(
+      'label' => t('Last access'),
+      'description' => t('The time that the user last accessed the site.'),
+      'type' => 'integer_field',
+    );
+    $properties['login'] = array(
+      'label' => t('Last login'),
+      'description' => t('The time that the user last logged in.'),
+      'type' => 'integer_field',
+    );
+    $properties['init'] = array(
+      'label' => t('Init'),
+      'description' => t('The email address used for initial account creation.'),
+      'type' => 'string_field',
+    );
+    $properties['roles'] = array(
+      'label' => t('Roles'),
+      'description' => t('The roles the user has.'),
+      'type' => 'string_field',
+    );
+    return $properties;
+  }
 }
diff --git a/core/modules/user/user.admin.inc b/core/modules/user/user.admin.inc
index 9946ae2..390050d 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -303,7 +303,7 @@ function user_admin_permissions($form, $form_state, $rid = NULL) {
     $role_names = array($rid => $role_names[$rid]);
   }
   // Fetch permissions for all roles or the one selected role.
-  $role_permissions = user_role_permissions($role_names);
+  $role_permissions = user_role_permissions(array_keys($role_names));
 
   // Store $role_names for use when saving the data.
   $form['role_names'] = array(
diff --git a/core/modules/user/user.api.php b/core/modules/user/user.api.php
index 652c5b5..ad5820d 100644
--- a/core/modules/user/user.api.php
+++ b/core/modules/user/user.api.php
@@ -18,7 +18,7 @@
  * This hook runs after a new user object has just been instantiated. It can be
  * used to set initial values, e.g. to provide defaults.
  *
- * @param \Drupal\user\Plugin\Core\Entity\User $user
+ * @param \Drupal\user\UserInterface $user
  *   The user object.
  */
 function hook_user_create(\Drupal\user\Plugin\Core\Entity\User $user) {
@@ -346,7 +346,7 @@ function hook_user_logout($account) {
  * The module should format its custom additions for display and add them to the
  * $account->content array.
  *
- * @param \Drupal\user\Plugin\Core\Entity\User $account
+ * @param \Drupal\user\UserInterface $account
  *   The user object on which the operation is being performed.
  * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
  *   The entity_display object holding the display options configured for the
@@ -359,7 +359,7 @@ function hook_user_logout($account) {
  * @see hook_user_view_alter()
  * @see hook_entity_view()
  */
-function hook_user_view(\Drupal\user\Plugin\Core\Entity\User $account, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) {
+function hook_user_view(\Drupal\user\UserInterface $account, \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display, $view_mode, $langcode) {
   // Only do the extra work if the component is configured to be displayed.
   // This assumes a 'mymodule_addition' extra field has been defined for the
   // user entity type in hook_field_extra_fields().
@@ -386,7 +386,7 @@ function hook_user_view(\Drupal\user\Plugin\Core\Entity\User $account, \Drupal\e
  *
  * @param $build
  *   A renderable array representing the user.
- * @param \Drupal\user\Plugin\Core\Entity\User $account
+ * @param \Drupal\user\UserInterface $account
  *   The user account being rendered.
  * @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
  *   The entity_display object holding the display options configured for the
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 42a79db..40a82b3 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -134,7 +134,7 @@ function user_entity_bundle_info() {
  */
 function user_uri($user) {
   return array(
-    'path' => 'user/' . $user->uid,
+    'path' => 'user/' . $user->id(),
   );
 }
 
@@ -155,7 +155,7 @@ function user_uri($user) {
  * @see user_format_name()
  */
 function user_label($entity_type, $entity) {
-  return user_format_name($entity);
+  return user_format_name($entity->getBCEntity());
 }
 
 /**
@@ -271,7 +271,12 @@ function user_field_extra_fields() {
  * @see \Drupal\Core\Entity\Query\QueryInterface
  */
 function user_load_multiple(array $uids = NULL, $reset = FALSE) {
-  return entity_load_multiple('user', $uids, $reset);
+  $entities = entity_load_multiple('user', $uids, $reset);
+  // Return BC-entities.
+  foreach ($entities as $id => $entity) {
+    $entities[$id] = $entity->getBCEntity();
+  }
+  return $entities;
 }
 
 /**
@@ -299,7 +304,8 @@ function user_load_multiple(array $uids = NULL, $reset = FALSE) {
  * @see user_load_multiple()
  */
 function user_load($uid, $reset = FALSE) {
-  return entity_load('user', $uid, $reset);
+  $user = entity_load('user', $uid, $reset);
+  return $user ? $user->getBCEntity() : FALSE;
 }
 
 /**
@@ -315,7 +321,7 @@ function user_load($uid, $reset = FALSE) {
  */
 function user_load_by_mail($mail) {
   $users = entity_load_multiple_by_properties('user', array('mail' => $mail));
-  return reset($users);
+  return $users ? reset($users)->getBCEntity() : FALSE;
 }
 
 /**
@@ -331,7 +337,7 @@ function user_load_by_mail($mail) {
  */
 function user_load_by_name($name) {
   $users = entity_load_multiple_by_properties('user', array('name' => $name));
-  return reset($users);
+  return $users ? reset($users)->getBCEntity() : FALSE;
 }
 
 /**
@@ -401,7 +407,7 @@ function user_password($length = 10) {
  * Determine the permissions for one or more roles.
  *
  * @param $roles
- *   An array whose keys are the role IDs of interest, such as $user->roles.
+ *   An array whose values are the role IDs of interest, such as $user->roles.
  *
  * @return
  *   An array indexed by role ID. Each value is an array whose keys are the
@@ -412,7 +418,7 @@ function user_role_permissions($roles) {
 
   $role_permissions = $fetch = array();
 
-  foreach ($roles as $rid => $name) {
+  foreach ($roles as $rid) {
     if (isset($cache[$rid])) {
       $role_permissions[$rid] = $cache[$rid];
     }
@@ -463,6 +469,9 @@ function user_access($string, $account = NULL) {
     $account = $user;
   }
 
+  // Make sure we are working with the BC decorator.
+  $account = $account instanceof User ? $account->getBCEntity() : $account;
+
   // User #1 has all privileges:
   if ($account->uid == 1) {
     return TRUE;
@@ -601,7 +610,7 @@ function user_search_execute($keys = NULL, $conditions = NULL) {
 /**
  * Implements hook_user_view().
  */
-function user_user_view(User $account, EntityDisplay $display) {
+function user_user_view(EntityInterface $account, EntityDisplay $display) {
   if ($display->getComponent('member_for')) {
     $account->content['member_for'] = array(
       '#type' => 'item',
@@ -722,6 +731,9 @@ function user_template_preprocess_default_variables_alter(&$variables) {
  */
 function template_preprocess_username(&$variables) {
   $account = $variables['account'];
+  if ($account instanceof User) {
+    $account = $account->getBCEntity();
+  }
 
   $variables['extra'] = '';
   if (empty($account->uid)) {
@@ -2102,12 +2114,11 @@ function user_multiple_role_edit($accounts, $operation, $rid) {
       $accounts = user_load_multiple($accounts);
       foreach ($accounts as $account) {
         // Skip adding the role to the user if they already have it.
-        if ($account !== FALSE && !isset($account->roles[$rid])) {
-          $roles = $account->roles + array($rid => $role_name);
+        if ($account !== FALSE && !array_search($rid, $account->roles)) {
           // For efficiency manually save the original account before applying
           // any changes.
           $account->original = clone $account;
-          $account->roles = $roles;
+          $account->roles[] = $rid;
           $account->save();
         }
       }
@@ -2116,8 +2127,8 @@ function user_multiple_role_edit($accounts, $operation, $rid) {
       $accounts = user_load_multiple($accounts);
       foreach ($accounts as $account) {
         // Skip removing the role from the user if they already don't have it.
-        if ($account !== FALSE && isset($account->roles[$rid])) {
-          $roles = array_diff($account->roles, array($rid => $role_name));
+        if ($account !== FALSE && $index = array_search($rid, $account->roles)) {
+          $roles = array_diff($account->roles, array($rid));
           // For efficiency manually save the original account before applying
           // any changes.
           $account->original = clone $account;
@@ -2284,9 +2295,10 @@ function user_build_filter_query(SelectInterface $query) {
     // the authenticated role. If so, then all users would be listed, and we can
     // skip adding it to the filter query.
     if ($key == 'permission') {
-      $account = entity_create('user', array());
-      $account->uid = 'user_filter';
-      $account->roles = array(DRUPAL_AUTHENTICATED_RID => 1);
+      $account = entity_create('user', array(
+        'uid' => 'user_filter',
+        'roles' => array(DRUPAL_AUTHENTICATED_RID),
+      ));
       if (user_access($value, $account)) {
         continue;
       }
@@ -2346,6 +2358,7 @@ function theme_user_signature($variables) {
  */
 function user_preferred_langcode($account, $type = NULL, $default = NULL) {
   $language_list = language_list();
+  $account = $account->getBCEntity();
   if (isset($type)) {
     $preferred_langcode = $account->{'preferred_' . $type . '_langcode'};
   }
diff --git a/core/modules/user/user.pages.inc b/core/modules/user/user.pages.inc
index 5f0cfab..f863d99 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -71,7 +71,7 @@ function user_pass_submit($form, &$form_state) {
 
   $account = $form_state['values']['account'];
   // Mail one time login URL and instructions using current language.
-  $mail = _user_mail_notify('password_reset', $account, $language_interface->langcode);
+  $mail = _user_mail_notify('password_reset', $account->getBCEntity(), $language_interface->langcode);
   if (!empty($mail)) {
     watchdog('user', 'Password reset instructions mailed to %name at %email.', array('%name' => $account->name, '%email' => $account->mail));
     drupal_set_message(t('Further instructions have been sent to your e-mail address.'));
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php
index 0d70b4c..686dcfb 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/access/AccessPluginBase.php
@@ -56,7 +56,7 @@ public function summaryTitle() {
   /**
    * Determine if the current user has access or not.
    *
-   * @param Drupal\user\User $account
+   * @param Drupal\user\UserInterface $account
    *   The user who wants to access this view.
    *
    * @return TRUE
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/cache/CachePluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/cache/CachePluginBase.php
index 7df986e..bd317f5 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/cache/CachePluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/cache/CachePluginBase.php
@@ -284,7 +284,7 @@ public function generateResultsKey() {
       }
       $key_data = array(
         'build_info' => $build_info,
-        'roles' => array_keys($user->roles),
+        'roles' => $user->roles,
         'super-user' => $user->uid == 1, // special caching for super user.
         'langcode' => language(LANGUAGE_TYPE_INTERFACE)->langcode,
         'base_url' => $GLOBALS['base_url'],
@@ -312,7 +312,7 @@ public function generateOutputKey() {
     if (!isset($this->outputKey)) {
       $key_data = array(
         'result' => $this->view->result,
-        'roles' => array_keys($user->roles),
+        'roles' => $user->roles,
         'super-user' => $user->uid == 1, // special caching for super user.
         'theme' => $GLOBALS['theme'],
         'langcode' => language(LANGUAGE_TYPE_INTERFACE)->langcode,
diff --git a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
index e0dd2d5..1645b47 100644
--- a/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
+++ b/core/modules/views/lib/Drupal/views/Plugin/views/filter/FilterPluginBase.php
@@ -1367,7 +1367,7 @@ public function storeExposedInput($input, $status) {
     // Check if we store exposed value for current user.
     global $user;
     $allowed_rids = empty($this->options['expose']['remember_roles']) ? array() : array_filter($this->options['expose']['remember_roles']);
-    $intersect_rids = array_intersect_key($allowed_rids, $user->roles);
+    $intersect_rids = array_intersect(array_keys($allowed_rids), $user->roles);
     if (empty($intersect_rids)) {
       return;
     }
diff --git a/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php b/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php
index b4c5118..c2dabc4 100644
--- a/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php
+++ b/core/modules/views/lib/Drupal/views/Tests/Plugin/AccessTest.php
@@ -37,11 +37,12 @@ protected function setUp() {
 
     $this->admin_user = $this->drupalCreateUser(array('access all views'));
     $this->web_user = $this->drupalCreateUser();
-    $this->web_role = current($this->web_user->roles);
+    $this->web_role = $this->web_user->roles[0];
 
     $this->normal_role = $this->drupalCreateRole(array());
     $this->normal_user = $this->drupalCreateUser(array('views_test_data test permission'));
-    $this->normal_user->roles[$this->normal_role] = $this->normal_role;
+    // @todo: How to add a new item to the roles field list.
+    $this->normal_user->getNGEntity()->roles[2]->value = $this->normal_role;
     // @todo when all the plugin information is cached make a reset function and
     // call it here.
   }
diff --git a/core/modules/views/views.module b/core/modules/views/views.module
index 61826f8..b96b2a0 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -753,9 +753,7 @@ function views_check_perm($perm, $account = NULL) {
 function views_check_roles($rids, $account = NULL) {
   global $user;
   $account = isset($account) ? $account : $user;
-  $roles = array_keys($account->roles);
-  $roles[] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
-  return user_access('access all views', $account) || array_intersect(array_filter($rids), $roles);
+  return user_access('access all views', $account) || array_intersect(array_filter($rids), $account->roles);
 }
 
 /**
diff --git a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
index 5877f28..315d098 100644
--- a/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
+++ b/core/modules/views_ui/lib/Drupal/views_ui/ViewUI.php
@@ -14,7 +14,7 @@
 use Drupal\views\Plugin\views\query\Sql;
 use Drupal\views\Plugin\Core\Entity\View;
 use Drupal\views\ViewStorageInterface;
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\user\UserInterface;
 
 /**
  * Stores UI related temporary settings.
@@ -942,7 +942,7 @@ public function language() {
   /**
    * Implements \Drupal\Core\TypedData\AccessibleInterface::access().
    */
-  public function access($operation = 'view', User $account = NULL) {
+  public function access($operation = 'view', UserInterface $account = NULL) {
     return $this->storage->access($operation, $account);
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
index f171580..c0d383c 100644
--- a/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
+++ b/core/tests/Drupal/Tests/Core/Route/RoleAccessCheckTest.php
@@ -112,17 +112,26 @@ public function roleAccessProvider() {
 
     // Setup one user with the first role, one with the second, one with both
     // and one final without any of these two roles.
-    $account_1 = new User(array('uid' => 1), 'user');
-    $account_1->roles[$rid_1] = $rid_1;
 
-    $account_2 = new User(array('uid' => 2), 'user');
-    $account_2->roles[$rid_2] = $rid_2;
+    $account_1 = (object) array(
+      'uid' => 1,
+      'roles' => array($rid_1),
+    );
 
-    $account_12 = new User(array('uid' => 3), 'user');
-    $account_12->roles[$rid_1] = $rid_1;
-    $account_12->roles[$rid_2] = $rid_2;
+    $account_2 = (object) array(
+      'uid' => 2,
+      'roles' => array($rid_2),
+    );
 
-    $account_none = new User(array('uid' => 4), 'user');
+    $account_12 = (object) array(
+      'uid' => 3,
+      'roles' => array($rid_1, $rid_2),
+    );
+
+    $account_none = (object) array(
+      'uid' => 1,
+      'roles' => array(),
+    );
 
     // Setup expected values; specify which paths can be accessed by which user.
     return array(
@@ -168,7 +177,7 @@ public function testRoleAccess($path, $grant_accounts, $deny_accounts) {
       $GLOBALS['user'] = $account;
 
       $subrequest = Request::create($path, 'GET');
-      $message = sprintf('Access denied for user %s with the roles %s on path: %s', $account->id(), implode(', ', $account->roles), $path);
+      $message = sprintf('Access denied for user %s with the roles %s on path: %s', $account->uid, implode(', ', $account->roles), $path);
       $has_access = $role_access_check->access($collection->get($path), $subrequest);
       $this->assertEmpty($has_access , $message);
     }
