diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php
index b43c112..0be8b84 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessController.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php
@@ -283,6 +283,12 @@ public function fieldAccess($operation, FieldDefinitionInterface $field_definiti
     // Get the default access restriction that lives within this field.
     $default = $items ? $items->defaultAccess($operation, $account) : TRUE;
 
+    // Get the default access restriction as specified by the access controller.
+    $entity_default = $this->checkFieldAccess($operation, $field_definition, $account, $items);
+
+    // Combine default access, denying access wins.
+    $default = $default && $entity_default;
+
     // Invoke hook and collect grants/denies for field access from other
     // modules. Our default access flag is masked under the ':default' key.
     $grants = array(':default' => $default);
@@ -312,4 +318,27 @@ public function fieldAccess($operation, FieldDefinitionInterface $field_definiti
     return FALSE;
   }
 
+  /**
+   * Default field access as determined by this access controller.
+   *
+   * @param string $operation
+   *   The operation access should be checked for.
+   *   Usually one of "view" or "edit".
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
+   *   The field definition.
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The user session for which to check access, or NULL to check access for
+   *   the current user. Defaults to NULL.
+   * @param \Drupal\Core\Field\FieldItemListInterface $items
+   *   (optional) The field values for which to check access, or NULL if access
+   *   is checked for the field definition, without any specific value
+   *   available. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if access is allowed, FALSE otherwise.
+   */
+  protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
+    return TRUE;
+  }
+
 }
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserFieldAccessTest.php b/core/modules/user/lib/Drupal/user/Tests/UserFieldAccessTest.php
new file mode 100644
index 0000000..616114d
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/Tests/UserFieldAccessTest.php
@@ -0,0 +1,243 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal\user\Tests\UserFieldAccessTest.
+ */
+
+namespace Drupal\user\Tests;
+
+use Drupal\system\Tests\Entity\EntityUnitTestBase;
+
+/**
+ * Tests the default field access on the user access controller.
+ */
+class UserFieldAccessTest extends EntityUnitTestBase {
+
+  /**
+   * The admin user account having the "administer users" permission.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $admin;
+
+  /**
+   * The user account having the "change own username" permission.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $owner;
+
+  /**
+   * The user account having the "access user profiles" permission.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $viewer;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'User base field access',
+      'description' => 'Tests access to base fields on the user entity.',
+      'group' => 'User',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->admin = $this->createUser(array(), array('administer users'));
+    $this->owner = $this->createUser(array(), array('change own username'));
+    $this->viewer = $this->createUser(array(), array('access user profiles'));
+  }
+
+  /**
+   * Asserts correct field access grants for a field.
+   */
+  public function assertFieldAccess($field, array $access_info) {
+    foreach ($access_info as $account => $info) {
+      foreach (array('view', 'edit') as $operation) {
+        $result = $info[$operation];
+        $message = format_string("User @field field access returns @result with operation '@op' for @account accessing @target", array(
+          '@field' => $field,
+          '@result' => !isset($result) ? 'null' : ($result ? 'true' : 'false'),
+          '@op' => $operation,
+          '@account' => $account,
+          '@target' => $info['target'],
+        ));
+        $this->assertEqual($result, $this->{$info['target']}->{$field}->access($operation, $this->{$account}), $message);
+      }
+    }
+  }
+
+  /**
+   * Tests default access for all base fields on the user entity.
+   */
+  public function testUserFieldAccess() {
+    // Since the test cases cannot interfere with each other we group them in
+    // one actual test method to improve test running performance.
+    $this->_testUserNameAccess();
+    $this->_testHiddenUserSettings();
+    $this->_testAdminFieldAccess();
+    $this->_testPasswordAccess();
+    $this->_testCreatedAccess();
+  }
+
+  /**
+   * Ensures user name access is working properly.
+   */
+  protected function _testUserNameAccess() {
+    $name_access = array(
+      // The viewer user is allowed to see user names on all accounts.
+      'viewer' => array(
+        'target' => 'viewer',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      'owner' => array(
+        'target' => 'viewer',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      'viewer' => array(
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      // The owner user is allowed to change its own user name.
+      'owner' => array(
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => TRUE,
+      ),
+      // The users-administrator user has full access.
+      'admin' => array(
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => TRUE,
+      ),
+    );
+    $this->assertFieldAccess('name', $name_access);
+  }
+
+  /**
+   * Tests that private user settings cannot be viewed by other users.
+   */
+  protected function _testHiddenUserSettings() {
+    foreach (array(
+      'preferred_langcode',
+      'preferred_admin_langcode',
+      'signature',
+      'signature_format',
+      'timezone',
+      'mail') as $field
+    ) {
+      $access_info = array(
+        'viewer' => array(
+          'target' => 'viewer',
+          'view' => TRUE,
+          'edit' => TRUE,
+        ),
+        'viewer' => array(
+          'target' => 'owner',
+          'view' => FALSE,
+          // Anyone with edit access to the user can also edit these fields.
+          'edit' => TRUE,
+        ),
+        'admin' => array(
+          'target' => 'owner',
+          'view' => TRUE,
+          'edit' => TRUE,
+        )
+      );
+      $this->assertFieldAccess($field, $access_info);
+    }
+  }
+
+  /**
+   * Tests that admin only user fields ore only accessible to admins.
+   */
+  protected function _testAdminFieldAccess() {
+    foreach (array(
+      'roles',
+      'status',
+      'access',
+      'login',
+      'init') as $field
+    ) {
+      $access_info = array(
+        'viewer' => array(
+          'target' => 'viewer',
+          'view' => FALSE,
+          'edit' => FALSE,
+        ),
+        'viewer' => array(
+          'target' => 'owner',
+          'view' => FALSE,
+          'edit' => FALSE,
+        ),
+        'admin' => array(
+          'target' => 'owner',
+          'view' => TRUE,
+          'edit' => TRUE,
+        )
+      );
+
+      $this->assertFieldAccess($field, $access_info);
+    }
+  }
+
+  /**
+   * Tests that paswords cannot be viewed, just edited.
+   */
+  protected function _testPasswordAccess() {
+    $pass_access = array(
+      'viewer' => array(
+        'target' => 'viewer',
+        'view' => FALSE,
+        'edit' => TRUE,
+      ),
+      'owner' => array(
+        'target' => 'viewer',
+        'view' => FALSE,
+        'edit' => TRUE,
+      ),
+      'admin' => array(
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => TRUE,
+      ),
+    );
+    $this->assertFieldAccess('pass', $pass_access);
+  }
+
+  /**
+   * Tests the user created field access.
+   */
+  protected function _testCreatedAccess() {
+    $created_access = array(
+      'viewer' => array(
+        'target' => 'viewer',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      'owner' => array(
+        'target' => 'viewer',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      'admin' => array(
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => TRUE,
+      ),
+    );
+    $this->assertFieldAccess('created', $created_access);
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/UserAccessController.php b/core/modules/user/lib/Drupal/user/UserAccessController.php
index 9aed19e..03efc0d 100644
--- a/core/modules/user/lib/Drupal/user/UserAccessController.php
+++ b/core/modules/user/lib/Drupal/user/UserAccessController.php
@@ -9,6 +9,8 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityAccessController;
+use Drupal\Core\Field\FieldDefinitionInterface;
+use Drupal\Core\Field\FieldItemListInterface;
 use Drupal\Core\Session\AccountInterface;
 
 /**
@@ -60,4 +62,60 @@ protected function viewAccess(EntityInterface $entity, $langcode, AccountInterfa
     return FALSE;
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  protected function checkFieldAccess($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
+    // Administrative users are allowed to edit and view all fields.
+    if ($account->hasPermission('administer users')) {
+      return TRUE;
+    }
+    // Flag to indicate if this user entity is the own user account.
+    $is_own_account = $items ? $items->getEntity()->id() == $account->id() : FALSE;
+    switch ($field_definition->getName()) {
+      case 'name':
+        // Allow view access to anyone with access to the entity.
+        if ($operation == 'view') {
+          return TRUE;
+        }
+        // Allow edit access for the own user name if the permission is
+        // satisfied.
+        return $is_own_account && $account->hasPermission('change own username');
+
+      case 'preferred_langcode':
+      case 'preferred_admin_langcode':
+      case 'signature':
+      case 'signature_format':
+      case 'timezone':
+      case 'mail':
+        // Allow view access to own mail address and other personalization
+        // settings.
+        if ($operation == 'view') {
+          return $is_own_account;
+        }
+        // Anyone that can edit the user can also this field.
+        return TRUE;
+
+      case 'pass':
+        // Allow editing the password, but not viewing it.
+        return $operation == 'edit';
+
+      case 'created':
+        if ($operation == 'view') {
+          return TRUE;
+        }
+        return FALSE;
+
+      case 'roles':
+      case 'status':
+      case 'access':
+      case 'login':
+      case 'init':
+        return FALSE;
+
+    }
+    // Allow access to all other fields.
+    return TRUE;
+  }
+
 }
diff --git a/core/modules/user/tests/Drupal/user/Tests/Entity/UserAccessControllerTest.php b/core/modules/user/tests/Drupal/user/Tests/Entity/UserAccessControllerTest.php
new file mode 100644
index 0000000..a2d6688
--- /dev/null
+++ b/core/modules/user/tests/Drupal/user/Tests/Entity/UserAccessControllerTest.php
@@ -0,0 +1,199 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\Tests\Entity\UserAccessControllerTest.
+ */
+
+namespace Drupal\user\Tests\Entity;
+
+use Drupal\Component\Utility\String;
+use Drupal\Tests\UnitTestCase;
+use Drupal\user\UserAccessController;
+
+/**
+ * Tests the user access controller.
+ *
+ * @group Drupal
+ * @group User
+ *
+ * @coversDefaultClass \Drupal\user\UserAccessController
+ */
+class UserAccessControllerTest extends UnitTestCase {
+
+  /**
+   * The user access controller to test.
+   *
+   * @var \Drupal\user\UserAccessController
+   */
+  protected $accessController;
+
+  /**
+   * The mock user account with view access.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $viewer;
+
+  /**
+   * The mock user account that is able to change their own account name.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $owner;
+
+  /**
+   * The mock adminstrative test user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $admin;
+
+  /**
+   * The mocked test field items.
+   *
+   * @var \Drupal\Core\Field\FieldItemList
+   */
+  protected $items;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'User access controller',
+      'description' => 'Tests the user access controller.',
+      'group' => 'User',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->viewer = $this->getMock('\Drupal\Core\Session\AccountInterface');
+    $this->viewer
+      ->expects($this->any())
+      ->method('hasPermission')
+      ->will($this->returnValue(FALSE));
+    $this->viewer
+      ->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue(1));
+
+    $this->owner = $this->getMock('\Drupal\Core\Session\AccountInterface');
+    $this->owner
+      ->expects($this->any())
+      ->method('hasPermission')
+      ->will($this->returnValueMap(array(
+        array('administer users', FALSE),
+        array('change own username', TRUE),
+      )));
+
+    $this->owner
+      ->expects($this->any())
+      ->method('id')
+      ->will($this->returnValue(2));
+
+    $this->admin = $this->getMock('\Drupal\Core\Session\AccountInterface');
+    $this->admin
+      ->expects($this->any())
+      ->method('hasPermission')
+      ->will($this->returnValue(TRUE));
+
+    $entity_type = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
+
+    $this->accessController = new UserAccessController($entity_type);
+    $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
+    $module_handler->expects($this->any())
+      ->method('getImplementations')
+      ->will($this->returnValue(array()));
+    $this->accessController->setModuleHandler($module_handler);
+
+    $this->items = $this->getMockBuilder('Drupal\Core\Field\FieldItemList')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $this->items
+      ->expects($this->any())
+      ->method('defaultAccess')
+      ->will($this->returnValue(TRUE));
+  }
+
+  /**
+   * Asserts correct field access grants for a field.
+   */
+  public function assertFieldAccess($field, $viewer, $target, $view, $edit, $field_definition) {
+    $this->items
+      ->expects($this->any())
+      ->method('getEntity')
+      ->will($this->returnValue($this->{$target}));
+
+    foreach (array('view' => $view, 'edit' => $edit) as $operation => $result) {
+      $message = String::format("User @field field access returns @result with operation '@op' for @account accessing @target", array(
+        '@field' => $field,
+        '@result' => !isset($result) ? 'null' : ($result ? 'true' : 'false'),
+        '@op' => $operation,
+        '@account' => $viewer,
+        '@target' => $target,
+      ));
+      $this->assertSame($result, $this->accessController->fieldAccess($operation, $field_definition, $this->{$viewer}, $this->items), $message);
+    }
+  }
+
+  /**
+   * Ensures user name access is working properly.
+   *
+   * @dataProvider userNameProvider
+   */
+  public function testUserNameAccess($viewer, $target, $view, $edit) {
+    $field_definition = $this->getMock('Drupal\Core\Field\FieldDefinitionInterface');
+    $field_definition->expects($this->any())
+      ->method('getName')
+      ->will($this->returnValue('name'));
+    $this->assertFieldAccess('name', $viewer, $target, $view, $edit, $field_definition);
+  }
+
+  /**
+   * Provides test data for estUserNameAccess().
+   */
+  public function userNameProvider() {
+    $name_access = array(
+      // The viewer user is allowed to see user names on all accounts.
+      array(
+        'viewer' => 'viewer',
+        'target' => 'viewer',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      array(
+        'viewer' => 'owner',
+        'target' => 'viewer',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      array(
+        'viewer' => 'viewer',
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => FALSE,
+      ),
+      // The owner user is allowed to change its own user name.
+      array(
+        'viewer' => 'owner',
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => TRUE,
+      ),
+      // The users-administrator user has full access.
+      array(
+        'viewer' => 'admin',
+        'target' => 'owner',
+        'view' => TRUE,
+        'edit' => TRUE,
+      ),
+    );
+    return $name_access;
+  }
+
+}
