 core/modules/taxonomy/src/Entity/Vocabulary.php    |  3 +-
 .../src/VocabularyAccessControlHandler.php         | 29 +++++++
 core/modules/taxonomy/taxonomy.routing.yml         |  2 +-
 .../Views/VocabularyAccessControlHandlerTest.php   | 94 ++++++++++++++++++++++
 4 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php
index a2d7eef..156de4c 100644
--- a/core/modules/taxonomy/src/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/src/Entity/Vocabulary.php
@@ -19,7 +19,8 @@
  *       "default" = "Drupal\taxonomy\VocabularyForm",
  *       "reset" = "Drupal\taxonomy\Form\VocabularyResetForm",
  *       "delete" = "Drupal\taxonomy\Form\VocabularyDeleteForm"
- *     }
+ *     },
+ *     "access" = "Drupal\taxonomy\VocabularyAccessControlHandler"
  *   },
  *   admin_permission = "administer taxonomy",
  *   config_prefix = "vocabulary",
diff --git a/core/modules/taxonomy/src/VocabularyAccessControlHandler.php b/core/modules/taxonomy/src/VocabularyAccessControlHandler.php
new file mode 100644
index 0000000..309b26e
--- /dev/null
+++ b/core/modules/taxonomy/src/VocabularyAccessControlHandler.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Drupal\taxonomy;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\EntityInterface;
+
+/**
+ * Defines the access control handler for the vocabulary entity type.
+ *
+ * @see \Drupal\taxonomy\Entity\Vocabulary
+ */
+class VocabularyAccessControlHandler extends EntityAccessControlHandler {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+    // Allow all users to view vocabulary config entities.
+    if ($operation === 'view') {
+      return AccessResult::allowed();
+    }
+
+    return parent::checkAccess($entity, $operation, $account);
+  }
+
+}
diff --git a/core/modules/taxonomy/taxonomy.routing.yml b/core/modules/taxonomy/taxonomy.routing.yml
index 8a3bd1a..e0046a0 100644
--- a/core/modules/taxonomy/taxonomy.routing.yml
+++ b/core/modules/taxonomy/taxonomy.routing.yml
@@ -74,7 +74,7 @@ entity.taxonomy_vocabulary.overview_form:
     _form: 'Drupal\taxonomy\Form\OverviewTerms'
     _title_callback: 'Drupal\taxonomy\Controller\TaxonomyController::vocabularyTitle'
   requirements:
-    _entity_access: 'taxonomy_vocabulary.view'
+    _permission: 'administer taxonomy'
 
 entity.taxonomy_term.canonical:
   path: '/taxonomy/term/{taxonomy_term}'
diff --git a/core/modules/taxonomy/tests/src/Unit/Views/VocabularyAccessControlHandlerTest.php b/core/modules/taxonomy/tests/src/Unit/Views/VocabularyAccessControlHandlerTest.php
new file mode 100644
index 0000000..3e145bd
--- /dev/null
+++ b/core/modules/taxonomy/tests/src/Unit/Views/VocabularyAccessControlHandlerTest.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Drupal\Tests\taxonomy\Unit\Views;
+
+use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\DependencyInjection\Container;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Session\UserSession;
+use Drupal\taxonomy\VocabularyAccessControlHandler;
+use Drupal\taxonomy\VocabularyInterface;
+use Drupal\Tests\UnitTestCase;
+use Prophecy\Argument;
+
+/**
+ * @group taxonomy
+ * @coversDefaultClass \Drupal\taxonomy\VocabularyAccessControlHandler
+ */
+class VocabularyAccessControlHandlerTest extends UnitTestCase {
+
+  /**
+   * The vocabulary access control handler to test.
+   *
+   * @var \Drupal\taxonomy\VocabularyAccessControlHandler
+   */
+  protected $vocabularyAccessController;
+
+  /**
+   * The stub vocabulary object for testing access.
+   *
+   * @var \Drupal\taxonomy\VocabularyInterface|\Prophecy\Prophecy\ProphecyInterface
+   */
+  protected $vocabulary;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp() {
+    parent::setUp();
+
+    $cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
+    $cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
+    $cache_contexts_manager->reveal();
+    $container = new Container();
+    $container->set('cache_contexts_manager', $cache_contexts_manager);
+    \Drupal::setContainer($container);
+
+    // Stub the Vocabulary.
+    $language = $this->prophesize(LanguageInterface::class);
+    $language->getId()->willReturn('en');
+    $vocabulary = $this->prophesize(VocabularyInterface::class);
+    $vocabulary->getEntityTypeId()->willReturn('taxonomy_vocabulary');
+    $vocabulary->uuid()->willReturn('5ed5e01f-663e-4f4f-b85a-265829b4c0a9');
+    $vocabulary->language()->willReturn($language->reveal());
+    $this->vocabulary = $vocabulary->reveal();
+
+    // Create VocabularyAccessControlHandler instance for testing.
+    $entity_type = $this->prophesize(EntityTypeInterface::class);
+    $entity_type->id()->willReturn('vocabulary_taxonomy');
+    $entity_type->getAdminPermission()->willReturn('administer taxonomy');
+    $module_handler = $this->prophesize(ModuleHandlerInterface::class);
+    $module_handler->invokeAll('entity_access', Argument::any())->willReturn([]);
+    $module_handler->invokeAll('taxonomy_vocabulary_access', Argument::any())->willReturn([]);
+    $this->vocabularyAccessController = new VocabularyAccessControlHandler($entity_type->reveal());
+    $this->vocabularyAccessController->setModuleHandler($module_handler->reveal());
+  }
+
+  /**
+   * @covers ::checkAccess
+   * @dataProvider vocabularyAccessProvider
+   */
+  public function testVocabularyAccess($has_administer_taxonomy_permission, $expected_view_access_result, $expected_edit_access_result) {
+    // Stub an account that has or does not have the 'administer taxonomy'
+    // permission.
+    $account = $this->prophesize(UserSession::class);
+    $account->id()->willReturn(2);
+    $account->hasPermission(Argument::is('administer taxonomy'))->willReturn($has_administer_taxonomy_permission);
+
+    $this->assertSame($expected_view_access_result, $this->vocabularyAccessController->access($this->vocabulary, 'view', $account->reveal()));
+    $this->assertSame($expected_edit_access_result, $this->vocabularyAccessController->access($this->vocabulary, 'edit', $account->reveal()));
+  }
+
+  /**
+   * @return array
+   */
+  public function vocabularyAccessProvider() {
+    return [
+      'user who does NOT have the "administer taxonomy" permission' => [FALSE, TRUE, FALSE],
+      'user who DOES have the "administer taxonomy" permission' => [TRUE, TRUE, TRUE],
+    ];
+  }
+
+}
