diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 48ee728..a73df20 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -50,6 +50,7 @@ function entity_get_info($entity_type = NULL) {
           'controller class' => 'Drupal\Core\Entity\DatabaseStorageController',
           'list controller class' => 'Drupal\Core\Entity\EntityListController',
           'render controller class' => 'Drupal\Core\Entity\EntityRenderController',
+          'access controller class' => 'Drupal\Core\Entity\EntityAccessController',
           'form controller class' => array(
             'default' => 'Drupal\Core\Entity\EntityFormController',
           ),
@@ -340,6 +341,27 @@ function entity_page_label(EntityInterface $entity, $langcode = NULL) {
 }
 
 /**
+ * Returns the entity access controller for the given entity type.
+ *
+ * @see hook_entity_info()
+ *
+ * @param string $entity_type
+ *   The type of the entity.
+ *
+ * @return \Drupal\Core\Entity\EntityAccessControllerInterface
+ *   An entity access controller instance.
+ */
+function entity_access_controller($entity_type) {
+  $controllers = &drupal_static(__FUNCTION__, array());
+  if (!isset($controllers[$entity_type])) {
+    $type_info = entity_get_info($entity_type);
+    $class = $type_info['access controller class'];
+    $controllers[$entity_type] = new $class($entity_type);
+  }
+  return $controllers[$entity_type];
+}
+
+/**
  * Returns an entity form controller for the given operation.
  *
  * Since there might be different scenarios in which an entity is edited,
diff --git a/core/lib/Drupal/Core/Entity/Entity.php b/core/lib/Drupal/Core/Entity/Entity.php
index 8f462de..d98f282 100644
--- a/core/lib/Drupal/Core/Entity/Entity.php
+++ b/core/lib/Drupal/Core/Entity/Entity.php
@@ -250,9 +250,17 @@ public function getIterator() {
 
   /**
    * Implements AccessibleInterface::access().
-   */
-  public function access(\Drupal\user\User $account = NULL) {
-    // TODO: Implement access() method.
+   *
+   * In addition to the access operations 'view' and 'edit' as defined by
+   * \Drupal\Core\TypedData\AccessibleInterface::access() the implementation
+   * supports the access operations 'create', 'update' and 'delete'.
+   */
+  public function access($operation = 'view', \Drupal\user\User $account = NULL) {
+    if ($operation == 'edit') {
+      // Map the 'edit' operation to 'update'.
+      $operation = 'update';
+    }
+    return entity_access_controller($this->entityType)->{"{$operation}Access"}($this, LANGUAGE_DEFAULT, $account);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php
new file mode 100644
index 0000000..80b54cb
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php
@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Entity\EntityAccessController.
+ */
+
+namespace Drupal\Core\Entity;
+
+use Drupal\user\User;
+
+/**
+ * Base class for entity access controllers.
+ *
+ * Defaults to FALSE (access denied) for 'view', 'create', 'update' and 'delete'
+ * access checks.
+ */
+class EntityAccessController implements EntityAccessControllerInterface {
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityAccessControllerInterface::viewAccess().
+   */
+  public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return FALSE;
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityAccessControllerInterface::createAccess().
+   */
+  public function createAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return FALSE;
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityAccessControllerInterface::updateAccess().
+   */
+  public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return FALSE;
+  }
+
+  /**
+   * Implements \Drupal\Core\Entity\EntityAccessControllerInterface::deleteAccess().
+   */
+  public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return FALSE;
+  }
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php
new file mode 100644
index 0000000..795a426
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php
@@ -0,0 +1,82 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\Core\Entity\EntityAccessControllerInterface.
+ */
+
+namespace Drupal\Core\Entity;
+
+/**
+ * Defines a common interface for entity access controller classes.
+ */
+interface EntityAccessControllerInterface {
+
+  /**
+   * Checks 'view' access for a given entity or entity translation.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to check 'view' access for.
+   * @param string $langcode
+   *   (optional) The language code for which to check access for. Defaults to
+   *   LANGUAGE_DEFAULT.
+   * @param \Drupal\user\User $account
+   *   (optional) The user for whom to check access for, or NULL to check access
+   *   for the current user. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if access was granted, FALSE otherwise.
+   */
+  public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, \Drupal\user\User $account = NULL);
+
+  /**
+   * Checks 'create' access for a given entity or entity translation.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to check 'create' access for.
+   * @param string $langcode
+   *   (optional) The language code for which to check access for. Defaults to
+   *   LANGUAGE_DEFAULT.
+   * @param \Drupal\user\User $account
+   *   (optional) The user for whom to check access for, or NULL to check access
+   *   for the current user. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if access was granted, FALSE otherwise.
+   */
+  public function createAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, \Drupal\user\User $account = NULL);
+
+  /**
+   * Checks 'update' access for a given entity or entity translation.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to check 'update' access for.
+   * @param string $langcode
+   *   (optional) The language code for which to check access for. Defaults to
+   *   LANGUAGE_DEFAULT.
+   * @param \Drupal\user\User $account
+   *   (optional) The user for whom to check access for, or NULL to check access
+   *   for the current user. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if access was granted, FALSE otherwise.
+   */
+  public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, \Drupal\user\User $account = NULL);
+
+  /**
+   * Checks 'delete' access for a given entity or entity translation.
+   *
+   * @param \Drupal\Core\Entity\EntityInterface $entity
+   *   The entity to check 'delete' access for.
+   * @param string $langcode
+   *   (optional) The language code for which to check access for. Defaults to
+   *   LANGUAGE_DEFAULT.
+   * @param \Drupal\user\User $account
+   *   (optional) The user for whom to check access for, or NULL to check access
+   *   for the current user. Defaults to NULL.
+   *
+   * @return bool
+   *   TRUE if access was granted, FALSE otherwise.
+   */
+  public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, \Drupal\user\User $account = NULL);
+}
diff --git a/core/lib/Drupal/Core/Entity/EntityInterface.php b/core/lib/Drupal/Core/Entity/EntityInterface.php
index 9b751d4..bf4733d 100644
--- a/core/lib/Drupal/Core/Entity/EntityInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityInterface.php
@@ -16,6 +16,10 @@
  *
  * When implementing this interface which extends Traversable, make sure to list
  * IteratorAggregate or Iterator before this interface in the implements clause.
+ *
+ * In addition to the access operations 'view' and 'edit' as supported by
+ * \Drupal\Core\TypedData\AccessibleInterface::access() the implementation has
+ * to support the access operations 'create', 'update' and 'delete'.
  */
 interface EntityInterface extends ComplexDataInterface, AccessibleInterface, TranslatableInterface {
 
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
index 0db4657..acc52fe 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/EntityTranslation.php
@@ -233,8 +233,12 @@ public function isEmpty() {
   /**
    * Implements AccessibleInterface::access().
    */
-  public function access(\Drupal\user\User $account = NULL) {
-    // @todo implement
+  public function access($operation = 'view', \Drupal\user\User $account = NULL) {
+    if ($operation == 'edit') {
+      // Map the 'edit' operation to 'update'.
+      $operation = 'update';
+    }
+    return entity_access_controller($this->parent->entityType())->{"{$operation}Access"}($this->parent, $this->langcode, $account);
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Field/Type/Field.php b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
index f4b4e5c..23864b2 100644
--- a/core/lib/Drupal/Core/Entity/Field/Type/Field.php
+++ b/core/lib/Drupal/Core/Entity/Field/Type/Field.php
@@ -297,7 +297,7 @@ public function __clone() {
   /**
    * Implements AccessibleInterface::access().
    */
-  public function access(User $account = NULL) {
+  public function access($operation = 'view', User $account = NULL) {
     // TODO: Implement access() method. Use item access.
   }
 }
diff --git a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
index 669f1d7..0e94857 100644
--- a/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
+++ b/core/lib/Drupal/Core/TypedData/AccessibleInterface.php
@@ -15,12 +15,18 @@
   /**
    * Checks data value access.
    *
+   * @param string $operation
+   *   (optional) The operation to be performed. Possible values are:
+   *   - edit
+   *   - view
+   *   Defaults to 'view'.
    * @param \Drupal\user\User $account
-   *   (optional) The user account to check access for. Defaults to the current
-   *   user.
+   *   (optional) The user for whom to check access for, or NULL to check access
+   *   for the current user. Defaults to NULL.
    *
    * @return bool
-   *   TRUE if the given user has access; otherwise FALSE.
+   *   TRUE if the given user has access for the given operation, FALSE
+   *   otherwise.
    */
-  public function access(\Drupal\user\User $account = NULL);
+  public function access($operation = 'view', \Drupal\user\User $account = NULL);
 }
diff --git a/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
new file mode 100644
index 0000000..f30da79
--- /dev/null
+++ b/core/modules/system/lib/Drupal/system/Tests/Entity/EntityAccessTest.php
@@ -0,0 +1,125 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\system\Tests\Entity\EntityAccessTest.
+ */
+
+namespace Drupal\system\Tests\Entity;
+
+use Drupal\Core\Language\Language;
+use Drupal\Core\TypedData\AccessibleInterface;
+use Drupal\simpletest\WebTestBase;
+use Drupal\user\User;
+
+/**
+ * Tests the entity access controller.
+ */
+class EntityAccessTest extends WebTestBase  {
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Entity access',
+      'description' => 'Tests entity access.',
+      'group' => 'Entity API',
+    );
+  }
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  public static $modules = array('entity_test', 'entity_access_test');
+
+  /**
+   * Asserts entity access correctly grants or denies access.
+   */
+  function assertEntityAccess($ops, AccessibleInterface $object, User $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'),
+        '@op' => $op,
+      ));
+
+      $this->assertEqual($result, $object->access($op, $account), $message);
+    }
+  }
+
+  /**
+   * Ensures entity access is properly working.
+   */
+  function testEntityAccess() {
+    // Set up a non-admin user that is allowed to view test entities.
+    $user = $this->drupalCreateUser(array('view test entity'));
+    $this->drupalLogin($user);
+
+    $entity = entity_create('entity_test', array(
+      'name' => 'test',
+    ));
+    $entity->save();
+
+    // The current user is allowed to view, create, update and delete entities.
+    $this->assertEntityAccess(array(
+      'create' => TRUE,
+      'update' => TRUE,
+      'delete' => TRUE,
+      'view' => TRUE,
+    ), $entity);
+
+    // The custom user is not allowed to view test entities.
+    $custom_user = $this->drupalCreateUser();
+    $this->assertEntityAccess(array(
+      'create' => TRUE,
+      'update' => TRUE,
+      'delete' => TRUE,
+      'view' => FALSE,
+    ), $entity, $custom_user);
+
+    // Check that the default access controller is used for entities that don't
+    // have a specific access controller defined.
+    $controller = entity_access_controller('entity_access_test');
+    $this->assertTrue(is_a($controller, '\Drupal\Core\Entity\EntityAccessController'), 'The default entity controller is used for the entity_access_test entity type.');
+
+    $entity = entity_create('entity_access_test', array());
+    $this->assertEntityAccess(array(
+      'create' => FALSE,
+      'update' => FALSE,
+      'delete' => FALSE,
+      'view' => FALSE,
+    ), $entity);
+  }
+
+  /**
+   * Ensures entity access for entity translations is properly working.
+   */
+  function testEntityTranslationAccess() {
+    // Enable translations for the test entity type.
+    variable_set('entity_test_translation', TRUE);
+    module_enable(array('locale'));
+
+    // Set up a non-admin user that is allowed to view test entity translations.
+    $user = $this->drupalCreateUser(array('view test entity translations'));
+    $this->drupalLogin($user);
+
+    // Create two test languages.
+    foreach (array('foo', 'bar') as $langcode) {
+      $language = new Language(array(
+        'langcode' => $langcode,
+        'name' => $this->randomString(),
+      ));
+      language_save($language);
+    }
+
+    $entity = entity_create('entity_test', array(
+      'name' => 'test',
+      'langcode' => 'foo',
+    ));
+    $entity->save();
+
+    $translation = $entity->getTranslation('bar');
+    $this->assertEntityAccess(array(
+      'view' => TRUE,
+    ), $translation);
+  }
+}
diff --git a/core/modules/system/tests/modules/entity_access_test/entity_access_test.info b/core/modules/system/tests/modules/entity_access_test/entity_access_test.info
new file mode 100644
index 0000000..d285089
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_access_test/entity_access_test.info
@@ -0,0 +1,6 @@
+name = "Entity access test"
+description = "Support module for testing entity access."
+package = Testing
+version = VERSION
+core = 8.x
+hidden = TRUE
diff --git a/core/modules/system/tests/modules/entity_access_test/entity_access_test.module b/core/modules/system/tests/modules/entity_access_test/entity_access_test.module
new file mode 100644
index 0000000..574efab
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_access_test/entity_access_test.module
@@ -0,0 +1,34 @@
+<?php
+
+/**
+ * @file
+ * Helper module for entity access tests.
+ */
+
+/**
+ * Implements hook_permission().
+ */
+function entity_access_test_permission() {
+  return array(
+    'view test entity' => array(
+      'title' => t('View test entities'),
+    ),
+    'view test entity translations' => array(
+      'title' => t('View translations of test entities'),
+    ),
+  );
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function entity_access_test_entity_info() {
+  return array(
+    'entity_access_test' => array(
+      'label' => 'Entity without access controller',
+      'entity keys' => array(
+        'id' => 'id',
+      ),
+    ),
+  );
+}
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.module b/core/modules/system/tests/modules/entity_test/entity_test.module
index 46def82..ba87cd1 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -13,6 +13,7 @@ function entity_test_entity_info() {
     'label' => t('Test entity'),
     'entity class' => 'Drupal\entity_test\EntityTest',
     'controller class' => 'Drupal\entity_test\EntityTestStorageController',
+    'access controller class' => 'Drupal\entity_test\EntityTestAccessController',
     'form controller class' => array(
       'default' => 'Drupal\entity_test\EntityTestFormController',
     ),
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
new file mode 100644
index 0000000..ada2944
--- /dev/null
+++ b/core/modules/system/tests/modules/entity_test/lib/Drupal/entity_test/EntityTestAccessController.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * @file
+ * Definition of Drupal\entity_test\EntityTestAccessController.
+ */
+
+namespace Drupal\entity_test;
+
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\EntityAccessControllerInterface;
+use Drupal\user\User;
+
+/**
+ * Access controller for the test entity.
+ */
+class EntityTestAccessController implements EntityAccessControllerInterface {
+
+  /**
+   * Implements EntityAccessInterface::view().
+   */
+  public function viewAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    if ($langcode != LANGUAGE_DEFAULT) {
+      return user_access('view test entity translations', $account);
+    }
+    return user_access('view test entity', $account);
+  }
+
+  /**
+   * Implements EntityAccessInterface::create().
+   */
+  public function createAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return TRUE;
+  }
+
+  /**
+   * Implements EntityAccessInterface::update().
+   */
+  public function updateAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return TRUE;
+  }
+
+  /**
+   * Implements EntityAccessInterface::delete().
+   */
+  public function deleteAccess(EntityInterface $entity, $langcode = LANGUAGE_DEFAULT, User $account = NULL) {
+    return TRUE;
+  }
+}
