diff --git a/entity_clone.module b/entity_clone.module
index f2bdfba..b1c2451 100644
--- a/entity_clone.module
+++ b/entity_clone.module
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
@@ -139,8 +140,39 @@ function entity_clone_entity_operation(EntityInterface $entity) {
  * Implements hook_entity_access().
  */
 function entity_clone_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
-  if ($operation === 'clone') {
-    return AccessResult::allowedIfHasPermission($account, 'clone ' . $entity->getEntityTypeId() . ' entity');
+  if ($operation !== 'clone') {
+    return AccessResult::neutral();
   }
-  return AccessResult::neutral();
+
+  $cache = new CacheableMetadata();
+  $cache->addCacheContexts(['user.permissions']);
+
+  // Deny access if the user cannot clone the entity.
+  $access = AccessResult::forbiddenIf(!$account->hasPermission('clone ' . $entity->getEntityTypeId() . ' entity'));
+  if ($access->isForbidden()) {
+    return $access->addCacheableDependency($cache);
+  }
+
+  // Deny access if the user can clone but cannot create new entities of this
+  // type. However, we have some exceptions in which the access control handler
+  // doesn't have a say in things. In these cases, we go based on the clone
+  // permission only.
+  $exceptions = [
+    'file',
+    'paragraph',
+  ];
+
+  if (in_array($entity->getEntityTypeId(), $exceptions)) {
+    return AccessResult::allowed()->addCacheableDependency($cache);
+  }
+
+  $handler = \Drupal::entityTypeManager()->getAccessControlHandler($entity->getEntityTypeId());
+  $access = $handler->createAccess($entity->bundle(), $account, [], TRUE);
+  if (!$access->isAllowed()) {
+    $cache->addCacheableDependency($access);
+    $forbidden = AccessResult::forbidden();
+    return $forbidden->addCacheableDependency($cache);
+  }
+
+  return AccessResult::allowed()->addCacheableDependency($cache);
 }
diff --git a/tests/src/Functional/EntityCloneEntityFormModeTest.php b/tests/src/Functional/EntityCloneEntityFormModeTest.php
index a310ab0..2e3acaa 100644
--- a/tests/src/Functional/EntityCloneEntityFormModeTest.php
+++ b/tests/src/Functional/EntityCloneEntityFormModeTest.php
@@ -17,7 +17,7 @@ class EntityCloneEntityFormModeTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = ['entity_clone'];
+  public static $modules = ['entity_clone', 'field_ui'];
 
   /**
    * Theme to enable by default
@@ -32,6 +32,7 @@ class EntityCloneEntityFormModeTest extends BrowserTestBase {
    */
   protected $permissions = [
     'clone entity_form_mode entity',
+    'administer display modes',
   ];
 
   /**
diff --git a/tests/src/Functional/EntityCloneEntityViewModeTest.php b/tests/src/Functional/EntityCloneEntityViewModeTest.php
index a06b4e7..1a7faf1 100644
--- a/tests/src/Functional/EntityCloneEntityViewModeTest.php
+++ b/tests/src/Functional/EntityCloneEntityViewModeTest.php
@@ -17,7 +17,7 @@ class EntityCloneEntityViewModeTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = ['entity_clone'];
+  public static $modules = ['entity_clone', 'field_ui'];
 
   /**
    * Theme to enable by default
@@ -32,6 +32,7 @@ class EntityCloneEntityViewModeTest extends BrowserTestBase {
    */
   protected $permissions = [
     'clone entity_view_mode entity',
+    'administer display modes',
   ];
 
   /**
diff --git a/tests/src/Functional/EntityCloneParagraphTest.php b/tests/src/Functional/EntityCloneParagraphTest.php
index 9a1bc1a..aa870ce 100644
--- a/tests/src/Functional/EntityCloneParagraphTest.php
+++ b/tests/src/Functional/EntityCloneParagraphTest.php
@@ -38,6 +38,7 @@ class EntityCloneParagraphTest extends NodeTestBase {
    */
   protected $permissions = [
     'clone node entity',
+    'bypass node access',
   ];
 
   /**
diff --git a/tests/src/Functional/EntityCloneShortcutSetTest.php b/tests/src/Functional/EntityCloneShortcutSetTest.php
index 017d267..be26497 100644
--- a/tests/src/Functional/EntityCloneShortcutSetTest.php
+++ b/tests/src/Functional/EntityCloneShortcutSetTest.php
@@ -32,6 +32,7 @@ class EntityCloneShortcutSetTest extends BrowserTestBase {
    */
   protected $permissions = [
     'clone shortcut_set entity',
+    'administer shortcuts',
   ];
 
   /**
diff --git a/tests/src/Functional/EntityCloneUserTest.php b/tests/src/Functional/EntityCloneUserTest.php
index 330ff04..08fa2df 100644
--- a/tests/src/Functional/EntityCloneUserTest.php
+++ b/tests/src/Functional/EntityCloneUserTest.php
@@ -32,6 +32,7 @@ class EntityCloneUserTest extends BrowserTestBase {
    */
   protected $permissions = [
     'clone user entity',
+    'administer users',
   ];
 
   /**
diff --git a/tests/src/Functional/EntityCloneViewTest.php b/tests/src/Functional/EntityCloneViewTest.php
index be26c1b..a2efac0 100644
--- a/tests/src/Functional/EntityCloneViewTest.php
+++ b/tests/src/Functional/EntityCloneViewTest.php
@@ -17,7 +17,7 @@ class EntityCloneViewTest extends BrowserTestBase {
    *
    * @var array
    */
-  public static $modules = ['entity_clone', 'views'];
+  public static $modules = ['entity_clone', 'views', 'views_ui'];
 
   /**
    * Theme to enable by default
@@ -32,6 +32,7 @@ class EntityCloneViewTest extends BrowserTestBase {
    */
   protected $permissions = [
     'clone view entity',
+    'administer views',
   ];
 
   /**
diff --git a/tests/src/Kernel/EntityCloneAccessTest.php b/tests/src/Kernel/EntityCloneAccessTest.php
new file mode 100644
index 0000000..7e626c4
--- /dev/null
+++ b/tests/src/Kernel/EntityCloneAccessTest.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Drupal\Tests\entity_clone\Kernel;
+
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\node\Entity\Node;
+use Drupal\node\Entity\NodeType;
+use Drupal\Tests\user\Traits\UserCreationTrait;
+
+/**
+ * Tests entity clone access.
+ *
+ * @group entity_clone
+ */
+class EntityCloneAccessTest extends KernelTestBase {
+
+  use UserCreationTrait;
+
+  /**
+    * {@inheritdoc}
+    */
+   public static $modules = [
+     'node',
+     'field',
+     'text',
+     'user',
+     'entity_clone',
+     'system',
+   ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->installEntitySchema('node');
+    $this->installEntitySchema('user');
+    $this->installSchema('system', ['sequences']);
+    $this->installSchema('node', ['node_access']);
+
+    $this->installConfig([
+      'node',
+      'user',
+      'system',
+      'entity_clone',
+    ]);
+
+    // Call the user module install process that creates the anonymous user
+    // and user 1.
+    $this->container->get('module_handler')->loadInclude('user', 'install');
+    user_install();
+
+    $node_type = NodeType::create([
+      'type' => 'page',
+      'id' => 'page',
+    ]);
+    $node_type->save();
+  }
+
+  /**
+   * Tests that users need to have the correct permissions to clone an entity.
+   */
+  public function testCloneAccess() {
+    $node = Node::create([
+      'type' => 'page',
+      'title' => 'My node to clone',
+      'status' => TRUE,
+    ]);
+
+    $node->save();
+
+    $user_no_permissions = $this->createUser(['access content']);
+    $user_that_can_create = $this->createUser(['access content', 'create page content']);
+    $user_that_can_clone = $this->createUser(['access content', 'clone node entity']);
+    $user_that_can_do_both = $this->createUser(['access content', 'clone node entity', 'create page content']);
+
+    $url = $node->toUrl('clone-form');
+
+    $access_control_handler = $this->container->get('entity_type.manager')->getAccessControlHandler('node');
+
+    // The user without permissions can view the content but cannot clone.
+    $this->assertTrue($access_control_handler->access($node, 'view', $user_no_permissions));
+    $this->assertFalse($access_control_handler->access($node, 'clone', $user_no_permissions));
+    $this->assertFalse($url->access($user_no_permissions));
+
+    // The user that can create content, cannot clone.
+    $this->assertTrue($access_control_handler->createAccess('page', $user_that_can_create));
+    $this->assertFalse($access_control_handler->access($node, 'clone', $user_that_can_create));
+    $this->assertFalse($url->access($user_that_can_create));
+
+    // The user that has clone permissions, but cannot create content, cannot
+    // clone.
+    $this->assertFalse($access_control_handler->createAccess('page', $user_that_can_clone));
+    $this->assertFalse($access_control_handler->access($node, 'clone', $user_that_can_clone));
+    $this->assertFalse($url->access($user_that_can_clone));
+
+    // The user that can do both, can clone.
+    $this->assertTrue($access_control_handler->createAccess('page', $user_that_can_do_both));
+    $this->assertTrue($access_control_handler->access($node, 'clone', $user_that_can_do_both));
+    $this->assertTrue($url->access($user_that_can_do_both));
+  }
+}
