diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 1109452..7ff45ce 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -17,6 +17,7 @@
 use Drupal\Core\Lock\DatabaseLockBackend;
 use Drupal\Core\Lock\LockBackendInterface;
 use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\Core\Entity\EntityBCDecorator;
 
 /**
  * @file
@@ -2052,14 +2053,13 @@ function drupal_hash_base64($data) {
  *   The user object.
  */
 function drupal_anonymous_user() {
-  $values = array(
+  return (object) array(
     'uid' => 0,
     'hostname' => ip_address(),
     '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 fbacae6..374fa40 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -5939,7 +5939,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/lib/Drupal/Core/Entity/DatabaseStorageController.php b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
index e57f4bb..965de84 100644
--- a/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
+++ b/core/lib/Drupal/Core/Entity/DatabaseStorageController.php
@@ -121,6 +121,9 @@ class DatabaseStorageController implements EntityStorageControllerInterface {
    */
   public function __construct($entityType) {
     $this->entityType = $entityType;
+    if (!function_exists('entity_get_info')) {
+      debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
+    }
     $this->entityInfo = entity_get_info($entityType);
     $this->entityCache = array();
     $this->hookLoadArguments = array();
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php
index 423281f..1fbce68 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessController.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php
@@ -94,6 +94,10 @@ protected function access(EntityInterface $entity, $operation, $langcode = LANGU
       $account = user_load($GLOBALS['user']->uid);
     }
 
+    if ($account instanceof User) {
+      $account = $account->getBCEntity();
+    }
+
     // We grant access to the entity if both of these conditions are met:
     // - No modules say to deny access.
     // - At least one module says to grant access.
diff --git a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
index 08be87c..d3a58cf 100644
--- a/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
+++ b/core/lib/Drupal/Core/Entity/EntityBCDecorator.php
@@ -90,6 +90,16 @@ public function &__get($name) {
       return $this->decorated->values[$name];
     }
 
+    // @todo: The EntityBCDecorator tries to be too intelligent and returns
+    //   a string but we actually want an array for roles.
+    if ($name == 'roles') {
+      $roles = array();
+      foreach ($this->getOriginalEntity()->roles as $role) {
+        $roles[] = $role->value;
+      }
+      return $roles;
+    }
+
     // We access the protected 'values' and 'fields' properties of the decorated
     // entity via the magic getter - which returns them by reference for us. We
     // do so, as providing references to these arrays would make $entity->values
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 8e9400f..1f64d87 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1611,7 +1611,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 715b63d..f5afcab 100644
--- a/core/modules/comment/comment.tokens.inc
+++ b/core/modules/comment/comment.tokens.inc
@@ -216,7 +216,7 @@ function comment_tokens($type, $tokens, array $data = array(), array $options =
     }
 
     if (($author_tokens = token_find_with_prefix($tokens, 'author')) && $account = $comment->uid->entity) {
-      $replacements += token_generate('user', $author_tokens, array('user' => $account), $options);
+      $replacements += token_generate('user', $author_tokens, array('user' => $account->getBCEntity()), $options);
     }
   }
   elseif ($type == 'node' & !empty($data['node'])) {
diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index 7907464..1388d13 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/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php
index cee642e..eb257dc 100644
--- a/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php
+++ b/core/modules/config/lib/Drupal/config/Tests/ConfigLocaleOverride.php
@@ -88,7 +88,7 @@ function testConfigLocaleUserOverride() {
     ));
 
     $user_config_context = config_context_enter('Drupal\user\UserConfigContext');
-    $user_config_context->setAccount($account);
+    $user_config_context->setAccount($account->getOriginalEntity());
     $config = config('config_test.system');
     $this->assertIdentical($config->get('foo'), 'fr bar');
     // Ensure the non-overriden value is still the same.
@@ -111,7 +111,7 @@ function testConfigLocaleUserOverride() {
     ));
 
     $config_factory = drupal_container()->get('config.factory');
-    $config_factory->enterContext($user_config_context->setAccount($account));
+    $config_factory->enterContext($user_config_context->setAccount($account->getOriginalEntity()));
     // Should not have to re-initialize the configuration object to get new
     // overrides as the new context will have a different uuid.
     $config = config('config_test.system');
@@ -127,7 +127,7 @@ function testConfigLocaleUserOverride() {
     ));
     // Create a new user config context to stack on top of the existign one.
     $en_user_config_context = config_context_enter('Drupal\user\UserConfigContext');
-    $en_user_config_context->setAccount($account);
+    $en_user_config_context->setAccount($account->getOriginalEntity());
     $config = config('config_test.system');
     $this->assertIdentical($config->get('foo'), 'en bar');
 
@@ -178,7 +178,7 @@ function testConfigLocaleUserAndGlobalOverride() {
     ));
 
     $user_config_context = config_context_enter('Drupal\user\UserConfigContext');
-    $user_config_context->setAccount($account);
+    $user_config_context->setAccount($account->getOriginalEntity());
     $config = config('config_test.system');
     $this->assertIdentical($config->get('foo'), 'fr bar');
     // Ensure the value overriden from global $conf works.
diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
index c4352cf..b3a9ed8 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
@@ -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 && $message->recipient->getOriginalEntity() instanceof User) {
       // Send to the user in the user's preferred language.
       $to = $message->recipient->mail;
       $recipient_langcode = user_preferred_langcode($message->recipient);
diff --git a/core/modules/file/file.field.inc b/core/modules/file/file.field.inc
index e3a7d7c..a3f355f 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 05b0cad..96d1b8d 100644
--- a/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
+++ b/core/modules/file/lib/Drupal/file/Tests/FileFieldWidgetTest.php
@@ -242,7 +242,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/node/lib/Drupal/node/NodeAccessController.php b/core/modules/node/lib/Drupal/node/NodeAccessController.php
index ec68b7e..5cf89ee 100644
--- a/core/modules/node/lib/Drupal/node/NodeAccessController.php
+++ b/core/modules/node/lib/Drupal/node/NodeAccessController.php
@@ -127,7 +127,7 @@ protected function accessGrants(EntityInterface $node, $operation, $langcode = L
     $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/node.module b/core/modules/node/node.module
index 36dcfe0..668b77d 100644
--- a/core/modules/node/node.module
+++ b/core/modules/node/node.module
@@ -2536,7 +2536,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)) {
-    $account = user_load($account->uid);
+    $account = entity_load('user', $account->uid);
   }
 
   $method = $op . 'Access';
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/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 4e7b6b1..293ce30 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -480,7 +480,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);
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 0642032..773cd18 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -82,7 +82,7 @@ function testEntityAccess() {
       'update' => FALSE,
       'delete' => FALSE,
       'view' => FALSE,
-    ), $entity, $custom_user);
+    ), $entity, $custom_user->getOriginalEntity());
   }
 
   /**
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..6269bed 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,8 @@
 
 namespace Drupal\system\Tests\Entity;
 
-use Drupal\user\Plugin\Core\Entity\User;
+use Drupal\Core\Entity\EntityInterface;
+
 
 /**
  * Tests the basic Entity API.
@@ -50,10 +51,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\Core\Entity\EntityInterface $user1
    *   The user to run the tests with.
    */
-  protected function assertCRUD($entity_type, User $user1) {
+  protected function assertCRUD($entity_type, EntityInterface $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 3c5679b..7cfc95c 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 b747e79..1209e7b 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 09e7a7a..4116b4e 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->getOriginalEntity()), '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->getOriginalEntity()), '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->getOriginalEntity()), '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..7815a8b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Plugin/ContextPluginTest.php
@@ -99,7 +99,7 @@ function testContext() {
 
     // Set an appropriate context value appropriately and check to make sure
     // its methods work as expected.
-    $user = entity_create('user', array('name' => $name));
+    $user = entity_create('user', array('name' => $name))->getOriginalEntity();
     $plugin->setContextValue('user', $user);
     $this->assertEqual($user->label(), $plugin->getTitle());
 
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/text/lib/Drupal/text/Tests/TextFieldTest.php b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
index f8c585b..16b19c8 100644
--- a/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
+++ b/core/modules/text/lib/Drupal/text/Tests/TextFieldTest.php
@@ -231,9 +231,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/EntityTranslationWorkflowsTest.php b/core/modules/translation_entity/lib/Drupal/translation_entity/Tests/EntityTranslationWorkflowsTest.php
index 9957552..741b806 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\Core\Entity\EntityInterface;
 
 /**
  * Tests entity translation workflows.
@@ -113,7 +113,7 @@ function testWorkflows() {
    *   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(EntityInterface $user, $expected_status) {
     $default_langcode = $this->langcodes[0];
     $languages = language_list();
     $args = array('@user_label' => $user->name);
diff --git a/core/modules/user/lib/Drupal/user/AccountFormController.php b/core/modules/user/lib/Drupal/user/AccountFormController.php
index 8f2f0c5..32fc112 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, EntityInterface $account)
     $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,20 @@ public function form(array $form, array &$form_state, EntityInterface $account)
   }
 
   /**
+   * Overrides Drupal\Core\Entity\EntityFormController::buildEntity().
+   */
+  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;
+    }
+    debug($form_state['values']);
+    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 fb7cbbb..4217f70 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,7 +7,7 @@
 
 namespace Drupal\user\Plugin\Core\Entity;
 
-use Drupal\Core\Entity\Entity;
+use Drupal\Core\Entity\EntityNG;
 use Drupal\Component\Annotation\Plugin;
 use Drupal\Core\Annotation\Translation;
 
@@ -38,7 +38,7 @@
  *   }
  * )
  */
-class User extends Entity {
+class User extends EntityNG {
 
   /**
    * The user ID.
@@ -59,7 +59,7 @@ class User extends Entity {
    *
    * @var string
    */
-  public $name = '';
+  public $name;
 
   /**
    * The user's password (hashed).
@@ -73,7 +73,7 @@ class User extends Entity {
    *
    * @var string
    */
-  public $mail = '';
+  public $mail;
 
   /**
    * The user's default theme.
@@ -109,7 +109,7 @@ class User extends Entity {
    *
    * @var integer
    */
-  public $access = 0;
+  public $access;
 
   /**
    * The timestamp when the user last logged in. A value of 0 means the user has
@@ -117,14 +117,14 @@ class User extends Entity {
    *
    * @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.
@@ -138,40 +138,84 @@ class User extends Entity {
    *
    * @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().
    */
   public function id() {
-    return $this->uid;
+    return $this->get('uid')->value;
+  }
+
+  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);
+  }
+
+  public function &__get($name) {
+    return parent::__get($name);
   }
 }
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 9d95b65..e46265b 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
@@ -29,8 +29,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.
@@ -133,8 +133,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) {
@@ -159,10 +159,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/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/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 38ca376..a1c23e5 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,17 @@ 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.');
+    debug($new_user->timezone->value);
+    $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.');
   }
 
   /**
@@ -240,7 +241,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;
@@ -268,9 +269,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/Views/AccessTestBase.php b/core/modules/user/lib/Drupal/user/Tests/Views/AccessTestBase.php
index 5455eaa..33cad6e 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->getOriginalEntity()->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 13b8c6b..aac9da0 100644
--- a/core/modules/user/lib/Drupal/user/UserAccessController.php
+++ b/core/modules/user/lib/Drupal/user/UserAccessController.php
@@ -20,7 +20,7 @@ class UserAccessController extends EntityAccessController {
    * Implements EntityAccessControllerInterface::viewAccess().
    */
   public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
-    $uid = $entity->uid;
+    $uid = $entity->uid->value;
     if (!$account) {
       $account = $GLOBALS['user'];
     }
@@ -33,7 +33,7 @@ public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT
       }
       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;
@@ -55,7 +55,7 @@ public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAU
     }
     // 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;
   }
 
   /**
@@ -68,7 +68,7 @@ public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAU
     // 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;
   }
 
 }
diff --git a/core/modules/user/lib/Drupal/user/UserStorageController.php b/core/modules/user/lib/Drupal/user/UserStorageController.php
index 3d8e981..c00937a 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,19 +52,25 @@ 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();
     }
+
+    // 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->getOriginalEntity();
+    }
     parent::save($entity);
   }
 
@@ -73,11 +79,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 +91,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 +112,28 @@ 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->uid->value == $GLOBALS['user']->uid) {
           drupal_session_regenerate();
         }
       }
 
       // Remove roles that are no longer enabled for the user.
-      $entity->roles = array_filter($entity->roles);
+      //$entity->roles = array_filter($entity->roles);
 
       // Reload user roles if provided.
-      if ($entity->roles != $entity->original->roles) {
+      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 +141,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 +178,123 @@ protected function postDelete($entities) {
       ->execute();
     drupal_container()->get('user.data')->delete(NULL, array_keys($entities));
   }
+
+  /**
+   * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::invokeHook().
+   */
+  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.
+    module_invoke_all($this->entityType . '_' . $hook, $entity->getBCEntity());
+    // Invoke the respective entity-level hook.
+    module_invoke_all('entity_' . $hook, $entity->getBCEntity(), $this->entityType);
+  }
+
+  /**
+   * Overrides \Drupal\Core\Entity\DataBaseStorageControllerNG::baseFieldDefinitions().
+   */
+  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 c3931d8..f619e59 100644
--- a/core/modules/user/user.admin.inc
+++ b/core/modules/user/user.admin.inc
@@ -690,7 +690,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.module b/core/modules/user/user.module
index 46f8807..2815218 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -156,7 +156,7 @@ function user_entity_bundle_info() {
  */
 function user_uri($user) {
   return array(
-    'path' => 'user/' . $user->uid,
+    'path' => 'user/' . $user->id(),
   );
 }
 
@@ -177,7 +177,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());
 }
 
 /**
@@ -293,7 +293,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;
 }
 
 /**
@@ -321,7 +326,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;
 }
 
 /**
@@ -337,7 +343,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;
 }
 
 /**
@@ -353,7 +359,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;
 }
 
 /**
@@ -434,7 +440,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];
     }
@@ -485,6 +491,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;
@@ -623,7 +632,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',
@@ -744,6 +753,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)) {
@@ -1742,7 +1754,7 @@ function user_mail($key, &$message, $params) {
   // allows the configuration objects to be localized for the user's language if
   // the locale module is enabled.
   $user_config_context = config_context_enter('Drupal\user\UserConfigContext');
-  $user_config_context->setAccount($params['account']);
+  $user_config_context->setAccount($params['account']->getOriginalEntity());
   $mail_config = config('user.mail');
 
    // We do not sanitize the token replacement, since the output of this
@@ -2097,12 +2109,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[count($account->roles)] = $rid;
           $account->save();
         }
       }
@@ -2111,8 +2122,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;
@@ -2341,6 +2352,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 140b767..4e57868 100644
--- a/core/modules/user/user.pages.inc
+++ b/core/modules/user/user.pages.inc
@@ -67,7 +67,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/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 6d262c4..4597a66 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..fcbddcb 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->getOriginalEntity()->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 58a7f35..2616b07 100644
--- a/core/modules/views/views.module
+++ b/core/modules/views/views.module
@@ -755,9 +755,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);
 }
 
 /**
