diff --git a/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php b/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php
index 76e87f4..61e6502 100644
--- a/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityAccessControlHandlerTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Access\AccessibleInterface;
 use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\entity_test\Entity\EntityTest;
 use Drupal\language\Entity\ConfigurableLanguage;
 
 /**
@@ -134,4 +135,60 @@ public function testHooks() {
     $this->assertEqual($state->get('entity_test_entity_access'), TRUE);
     $this->assertEqual($state->get('entity_test_entity_test_access'), TRUE);
   }
+
+  /**
+   * Verifies that EntityAccessControlHandler always calls ::checkAccess().
+   *
+   * Regression test for https://www.drupal.org/node/2204363.
+   */
+  public function testCheckAccessRunsAlways() {
+    $state = $this->container->get('state');
+
+    $operation = 'scream';
+
+    $entity = EntityTest::create([
+      'name' => 'checkAccess() test',
+    ]);
+    $entity->save();
+
+    // Reset the state, so we can cleanly check whether the hooks
+    $reset = function() use ($state) {
+      // Reset the state, so we can once again check if the hooks and
+      // ::checkAccess() are called.
+      $state->set('entity_test_entity_access', FALSE);
+      $state->set('entity_test_entity_test_access', FALSE);
+      $state->set('EntityTestAccessControlHandler::checkAccess', FALSE);
+      $this->assertFalse($state->get('entity_test_entity_access'));
+      $this->assertFalse($state->get('entity_test_entity_test_access'));
+      $this->assertFalse($state->get('EntityTestAccessControlHandler::checkAccess'));
+      $this->container->get('entity.manager')->getAccessControlHandler('entity_test')->resetCache();
+    };
+
+
+    // Make sure that >0 of hook_entity_access() and hook_ENTITY_TYPE_access()
+    // return an access result that grants access. In this situation, Drupal
+    // did *not* use to invoke ::checkAccess(), but it should, to match the
+    // developer's expectations. ::checkAccess() should still be able to forbid
+    // access.
+    $reset();
+    $state->set('entity_test_entity_access.' . $operation . '.' . $entity->id(), TRUE);
+    $entity->access($operation);
+
+    $this->assertTrue($state->get('entity_test_entity_access'), 'hook_entity_access() executed.');
+    $this->assertTrue($state->get('entity_test_entity_test_access'), 'hook_ENTITY_TYPE_entity_access() executed.');
+    $this->assertTrue($state->get('EntityTestAccessControlHandler::checkAccess'), 'EntityAccessControlHandler::checkAccess() executed.');
+
+
+    // Make sure both hook_entity_access() and hook_ENTITY_TYPE_access() return
+    // access results that neither allow nor forbid access. In this situation,
+    // Drupal has *always* invoked ::checkAccess().
+    $reset();
+    $state->set('entity_test_entity_access.' . $operation . '.' . $entity->id(), FALSE);
+    $entity->access($operation);
+
+    $this->assertTrue($state->get('entity_test_entity_access'), 'hook_entity_access() executed.');
+    $this->assertTrue($state->get('entity_test_entity_test_access'), 'hook_ENTITY_TYPE_entity_access() executed.');
+    $this->assertTrue($state->get('EntityTestAccessControlHandler::checkAccess'), 'EntityAccessControlHandler::checkAccess() executed.');
+  }
+
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php b/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
index 95efd80..18affff 100644
--- a/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
+++ b/core/modules/system/tests/modules/entity_test/src/EntityTestAccessControlHandler.php
@@ -30,6 +30,8 @@ class EntityTestAccessControlHandler extends EntityAccessControlHandler {
    * {@inheritdoc}
    */
   protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
+    \Drupal::state()->set('EntityTestAccessControlHandler::checkAccess', TRUE);
+
     if ($operation === 'view') {
       if ($langcode != LanguageInterface::LANGCODE_DEFAULT) {
         return AccessResult::allowedIfHasPermission($account, 'view test entity translations');
