diff --git a/core/lib/Drupal/Core/Entity/EntityAccessCheck.php b/core/lib/Drupal/Core/Entity/EntityAccessCheck.php
index 04412e9..99bba7c 100644
--- a/core/lib/Drupal/Core/Entity/EntityAccessCheck.php
+++ b/core/lib/Drupal/Core/Entity/EntityAccessCheck.php
@@ -45,17 +45,40 @@ public function access(Route $route, RouteMatchInterface $route_match, AccountIn
     // Split the entity type and the operation.
     $requirement = $route->getRequirement('_entity_access');
     list($entity_type, $operation) = explode('.', $requirement);
-    // If there is valid entity of the given entity type, check its access.
     $parameters = $route_match->getParameters();
-    if ($parameters->has($entity_type)) {
-      $entity = $parameters->get($entity_type);
-      if ($entity instanceof EntityInterface) {
+    // If there is valid entity of the given entity type, check its access.
+    foreach ($route->getOption('parameters') as $name => $options) {
+      $option_entity_type = $this->getEntityTypeFromDefaults($options, $route_match->getRawParameters()->all());
+      if (isset($options['type']) && $option_entity_type == $entity_type && ($entity = $parameters->get($name)) && $entity instanceof EntityInterface) {
         return $entity->access($operation, $account, TRUE);
       }
     }
+
     // No opinion, so other access checks should decide if access should be
     // allowed or not.
     return AccessResult::neutral();
   }
 
+  /**
+   * Determines the entity type ID given a route definition and route defaults.
+   *
+   * @param mixed $definition
+   *   The parameter definition provided in the route options.
+   * @param array $defaults
+   *   The route defaults array.
+   *
+   * @return string
+   *   The entity type ID.
+   */
+  protected function getEntityTypeFromDefaults($definition, array $defaults) {
+    $entity_type_id = substr($definition['type'], strlen('entity:'));
+
+    // If the entity type is dynamic, it will be pulled from the route defaults.
+    if (strpos($entity_type_id, '{') === 0) {
+      $entity_type_slug = substr($entity_type_id, 1, -1);
+      $entity_type_id = $defaults[$entity_type_slug];
+    }
+    return $entity_type_id;
+  }
+
 }
diff --git a/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php b/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php
index 1aa35b9..91d4314 100644
--- a/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php
+++ b/core/modules/content_translation/src/Routing/ContentTranslationRouteSubscriber.php
@@ -69,6 +69,7 @@ protected function alterRoutes(RouteCollection $collection) {
           'entity_type_id' => $entity_type_id,
         ),
         array(
+          '_entity_access' =>  $entity_type_id . '.view',
           '_access_content_translation_overview' => $entity_type_id,
         ),
         array(
@@ -94,6 +95,7 @@ protected function alterRoutes(RouteCollection $collection) {
 
         ),
         array(
+          '_entity_access' =>  $entity_type_id . '.view',
           '_access_content_translation_manage' => 'create',
         ),
         array(
diff --git a/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php b/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php
index bb7597c..9a11238 100644
--- a/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php
+++ b/core/modules/content_translation/src/Tests/ContentTestTranslationUITest.php
@@ -35,11 +35,13 @@ protected function setUp() {
     parent::setUp();
   }
 
+
+
   /**
    * Overrides \Drupal\content_translation\Tests\ContentTranslationUITestBase::getTranslatorPermission().
    */
   protected function getTranslatorPermissions() {
-    return array_merge(parent::getTranslatorPermissions(), array('administer entity_test content'));
+    return array_merge(parent::getTranslatorPermissions(), array('administer entity_test content', 'view test entity'));
   }
 
 }
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php
index 8d0c063..44ff2e6 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationOperationsTest.php
@@ -9,6 +9,7 @@
 
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\node\Tests\NodeTestBase;
+use Drupal\user\Entity\Role;
 
 /**
  * Tests the content translation operations available in the content listing.
@@ -75,6 +76,33 @@ function testOperationTranslateLink() {
     $this->drupalLogin($this->baseUser2);
     $this->drupalGet('admin/content');
     $this->assertLinkByHref('node/' . $node->id() . '/translations');
+
+    // Ensure that an unintended misconfiguration of permissions does not open
+    // access to the translation form. @see https://www.drupal.org/node/2558905
+    $this->drupalLogout();
+    user_role_change_permissions(
+      Role::AUTHENTICATED_ID,
+      [
+        'create content translations' => TRUE,
+        'access content' => FALSE,
+      ]
+    );
+    $this->drupalLogin($this->baseUser1);
+    $this->drupalGet('node/' . $node->id() . '/translations');
+    $this->assertResponse(403);
+
+    // Ensure that the translation overview is also not accessible when the user
+    // has 'access content', but the node is not published.
+    user_role_change_permissions(
+      Role::AUTHENTICATED_ID,
+      [
+        'create content translations' => TRUE,
+        'access content' => TRUE,
+      ]
+    );
+    $node->setPublished(FALSE)->save();
+    $this->drupalGet('node/' . $node->id() . '/translations');
+    $this->assertResponse(403);
   }
 
 }
diff --git a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
index 223bb81..b602be0 100644
--- a/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
+++ b/core/modules/content_translation/src/Tests/ContentTranslationWorkflowsTest.php
@@ -39,6 +39,16 @@ protected function setUp() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  protected function getTranslatorPermissions() {
+    $permissions = parent::getTranslatorPermissions();
+    $permissions[] = 'view test entity';
+
+    return $permissions;
+  }
+
+  /**
    * Overrides \Drupal\content_translation\Tests\ContentTranslationTestBase::getEditorPermissions().
    */
   protected function getEditorPermissions() {
@@ -109,7 +119,7 @@ function testWorkflows() {
     $ops = array('create' => t('Add'), 'update' => t('Edit'), 'delete' => t('Delete'));
     $translations_url = $this->entity->urlInfo('drupal:content-translation-overview');
     foreach ($ops as $current_op => $item) {
-      $user = $this->drupalCreateUser(array($this->getTranslatePermission(), "$current_op content translations"));
+      $user = $this->drupalCreateUser(array($this->getTranslatePermission(), "$current_op content translations", 'view test entity'));
       $this->drupalLogin($user);
       $this->drupalGet($translations_url);
 
diff --git a/core/modules/content_translation/src/Tests/Views/TranslationLinkTest.php b/core/modules/content_translation/src/Tests/Views/TranslationLinkTest.php
index 485f6f5..bb349e2 100644
--- a/core/modules/content_translation/src/Tests/Views/TranslationLinkTest.php
+++ b/core/modules/content_translation/src/Tests/Views/TranslationLinkTest.php
@@ -55,6 +55,15 @@ protected function setUp() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  protected function getTranslatorPermissions() {
+    $permissions = parent::getTranslatorPermissions();
+    $permissions[] = 'access user profiles';
+    return $permissions;
+  }
+
+  /**
    * Tests the content translation overview link field handler.
    */
   public function testTranslationLink() {
diff --git a/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php b/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
index e3b1087..1947114 100644
--- a/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
+++ b/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
@@ -54,8 +54,9 @@ public static function createInstance(ContainerInterface $container, EntityTypeI
   protected function checkAccess(EntityInterface $entity, $operation, $langcode, AccountInterface $account) {
     switch ($operation) {
       case 'view':
-        // There is no direct view.
-        return AccessResult::neutral();
+        // There is no direct viewing of a menu link, but still for purposes of
+        // content_translation we need a generic way to check access.
+        return AccessResult::allowedIfHasPermission($account, 'administer menu');
 
       case 'update':
         if (!$account->hasPermission('administer menu')) {
diff --git a/core/modules/rest/src/Tests/ResourceTest.php b/core/modules/rest/src/Tests/ResourceTest.php
index f55ad54..f699a4b 100644
--- a/core/modules/rest/src/Tests/ResourceTest.php
+++ b/core/modules/rest/src/Tests/ResourceTest.php
@@ -6,6 +6,8 @@
  */
 
 namespace Drupal\rest\Tests;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\user\Entity\Role;
 
 /**
  * Tests the structure of a REST resource.
@@ -38,6 +40,10 @@ protected function setUp() {
     // Create an entity programmatically.
     $this->entity = $this->entityCreate('entity_test');
     $this->entity->save();
+
+    Role::load(AccountInterface::ANONYMOUS_ROLE)
+      ->grantPermission('view test entity')
+      ->save();
   }
 
   /**
diff --git a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
index a80b984..5aeef20 100644
--- a/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
+++ b/core/modules/system/src/Tests/Entity/EntityViewControllerTest.php
@@ -39,6 +39,7 @@ protected function setUp() {
       $this->entities[] = $entity_test;
     }
 
+    $this->drupalLogin($this->drupalCreateUser(['view test entity']));
   }
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml
index 630f715..4759947 100644
--- a/core/modules/system/tests/modules/entity_test/entity_test.routing.yml
+++ b/core/modules/system/tests/modules/entity_test/entity_test.routing.yml
@@ -4,7 +4,7 @@ entity.entity_test.canonical:
     _entity_view: 'entity_test.full'
     _title: 'Test full view mode'
   requirements:
-    _access: 'TRUE'
+    _entity_access: 'entity_test.view'
 
 entity.entity_test.render_options:
   path: '/entity_test_converter/{foo}'
@@ -15,7 +15,7 @@ entity.entity_test.render_options:
   defaults:
     _entity_view: 'entity_test.full'
   requirements:
-    _access: 'TRUE'
+    _entity_access: 'entity_test.view'
 
 entity.entity_test.render_no_view_mode:
   path: '/entity_test_no_view_mode/{entity_test}'
diff --git a/core/modules/views/src/Tests/Handler/FieldEntityLinkTest.php b/core/modules/views/src/Tests/Handler/FieldEntityLinkTest.php
index 01a66ec..0ab8409 100644
--- a/core/modules/views/src/Tests/Handler/FieldEntityLinkTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldEntityLinkTest.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Session\AccountInterface;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\simpletest\UserCreationTrait;
+use Drupal\user\Entity\Role;
 use Drupal\views\Tests\ViewKernelTestBase;
 use Drupal\views\Views;
 
@@ -51,6 +52,7 @@ protected function setUpFixtures() {
 
     $this->installEntitySchema('user');
     $this->installEntitySchema('entity_test');
+    $this->installConfig(['user']);
 
     // Create some test entities.
     for ($i = 0; $i < 5; $i++) {
@@ -58,7 +60,11 @@ protected function setUpFixtures() {
     }
 
     // Create and admin user.
-    $this->adminUser = $this->createUser([], FALSE, TRUE);
+    $this->adminUser = $this->createUser(['view test entity'], FALSE, TRUE);
+
+    Role::load(AccountInterface::ANONYMOUS_ROLE)
+      ->grantPermission('view test entity')
+      ->save();
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php b/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php
index 0865933..287f5e6 100644
--- a/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php
+++ b/core/tests/Drupal/Tests/Core/Entity/EntityAccessCheckTest.php
@@ -32,7 +32,7 @@ public function testAccess() {
     $container->set('cache_contexts_manager', $cache_contexts_manager);
     \Drupal::setContainer($container);
 
-    $route = new Route('/foo', array(), array('_entity_access' => 'node.update'));
+    $route = new Route('/foo/{var_name}', array(), array('_entity_access' => 'node.update'), ['parameters' => ['var_name' => ['type' => 'entity:node']]]);
     $upcasted_arguments = new ParameterBag();
     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
     $route_match->expects($this->once())
@@ -45,7 +45,7 @@ public function testAccess() {
       ->method('access')
       ->will($this->returnValue(AccessResult::allowed()->cachePerPermissions()));
     $access_check = new EntityAccessCheck();
-    $upcasted_arguments->set('node', $node);
+    $upcasted_arguments->set('var_name', $node);
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
     $access = $access_check->access($route, $route_match, $account);
     $this->assertEquals(AccessResult::allowed()->cachePerPermissions(), $access);
