diff --git a/entity_reference_integrity.info.yml b/entity_reference_integrity.info.yml
index afb76b8..f93efb9 100644
--- a/entity_reference_integrity.info.yml
+++ b/entity_reference_integrity.info.yml
@@ -1,6 +1,6 @@
 name: Entity Reference Integrity
 description: Protect entities from being deleted if they are the target of an entity reference field.
-core_version_requirement: ^10.2 || ^11
+core_version_requirement: ^11.2 || ^12
 type: module
 
 package: Entity Reference Integrity
diff --git a/entity_reference_integrity.module b/entity_reference_integrity.module
index 655f379..b3aedce 100644
--- a/entity_reference_integrity.module
+++ b/entity_reference_integrity.module
@@ -5,16 +5,13 @@
  * Module file.
  */
 
-use Drupal\entity_reference_integrity\EntityReferenceIntegrityEntityHandler;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\entity_reference_integrity\Hook\EntityReferenceIntegrityHooks;
 
 /**
  * Implements hook_entity_type_alter().
  */
+#[LegacyHook]
 function entity_reference_integrity_entity_type_alter(array &$entity_types) {
-  /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
-  foreach ($entity_types as $entity_type) {
-    if (!$entity_type->hasHandlerClass('entity_reference_integrity')) {
-      $entity_type->setHandlerClass('entity_reference_integrity', EntityReferenceIntegrityEntityHandler::class);
-    }
-  }
+  \Drupal::service(EntityReferenceIntegrityHooks::class)->entityTypeAlter($entity_types);
 }
diff --git a/entity_reference_integrity.services.yml b/entity_reference_integrity.services.yml
index 34f1af0..9c3657d 100644
--- a/entity_reference_integrity.services.yml
+++ b/entity_reference_integrity.services.yml
@@ -2,3 +2,7 @@ services:
   entity_reference_integrity.field_map:
     class: \Drupal\entity_reference_integrity\DependencyFieldMapGenerator
     arguments: ['@entity_field.manager', '@entity_type.manager', 'entity_reference', 'target_type']
+
+  Drupal\entity_reference_integrity\Hook\EntityReferenceIntegrityHooks:
+    class: Drupal\entity_reference_integrity\Hook\EntityReferenceIntegrityHooks
+    autowire: true
diff --git a/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.info.yml b/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.info.yml
index 7b46c2c..5a90253 100644
--- a/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.info.yml
+++ b/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.info.yml
@@ -1,7 +1,7 @@
 name: Entity Reference Integrity Enforce
 description: Enforce reference integrity on entities.
 package: Entity Reference Integrity
-core_version_requirement: ^10.2 || ^11
+core_version_requirement: ^11.2 || ^12
 type: module
 
 dependencies:
diff --git a/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.module b/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.module
index 80caa24..85a28e0 100644
--- a/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.module
+++ b/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.module
@@ -5,70 +5,34 @@
  * Module file.
  */
 
-use Drupal\Core\Access\AccessResult;
-use Drupal\Core\Access\AccessResultForbidden;
-use Drupal\Core\Action\Plugin\Action\DeleteAction as CoreDeleteAction;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\entity_reference_integrity_enforce\Hook\EntityReferenceIntegrityEnforceHooks;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
-use Drupal\entity_reference_integrity\EntityReferenceIntegrityEntityHandler;
-use Drupal\entity_reference_integrity_enforce\FormAlter;
-use Drupal\entity_reference_integrity_enforce\EntityPredelete;
-use Drupal\entity_reference_integrity_enforce\Plugin\Action\DeleteAction;
 
 /**
  * Implements hook_form_alter().
  */
+#[LegacyHook]
 function entity_reference_integrity_enforce_form_alter(&$form, FormStateInterface $form_state, $form_id) {
-  \Drupal::service('class_resolver')
-    ->getInstanceFromDefinition(FormAlter::class)
-    ->formAlter($form, $form_state, $form_id);
+  \Drupal::service(EntityReferenceIntegrityEnforceHooks::class)->formAlter($form, $form_state, $form_id);
 }
 
 /**
  * Implements hook_entity_predelete().
  */
+#[LegacyHook]
 function entity_reference_integrity_enforce_entity_predelete(EntityInterface $entity) {
-  \Drupal::service('class_resolver')
-    ->getInstanceFromDefinition(EntityPredelete::class)
-    ->entityDelete($entity);
+  \Drupal::service(EntityReferenceIntegrityEnforceHooks::class)->entityPredelete($entity);
 }
 
 /**
  * Implements hook_entity_access().
  */
+#[LegacyHook]
 function entity_reference_integrity_enforce_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
-
-  // Only check access for delete operations.
-  if ($operation != 'delete') {
-    return AccessResult::neutral();
-  }
-
-  // Only check access for valid routes. This can return NULL.
-  $route = \Drupal::routeMatch()->getRouteObject();
-  if (empty($route)) {
-    return AccessResult::neutral();
-  }
-
-  // Only check access for API endpoints by checking the route _format.
-  // @todo Check formats for other API endpoints such as GraphQL and REST.
-  $api_formats = ['api_json'];
-  $format = $route->getRequirement('_format');
-  if (empty($format) || !in_array($format, $api_formats)) {
-    return AccessResult::neutral();
-  }
-
-  /** @var \Drupal\entity_reference_integrity\EntityReferenceIntegrityEntityHandler $entity_reference_integrity_handler */
-  $entity_reference_integrity_handler = \Drupal::entityTypeManager()->getHandler($entity->getEntityTypeId(), 'entity_reference_integrity');
-  $enabled_entity_type_ids = \Drupal::configFactory()->get('entity_reference_integrity_enforce.settings')->get('enabled_entity_type_ids');
-
-  // Finally deny access if the entity has dependents.
-  if (in_array($entity->getEntityTypeId(), $enabled_entity_type_ids, TRUE) && $entity_reference_integrity_handler->hasDependents($entity)) {
-    $reason = EntityReferenceIntegrityEntityHandler::getAccessDeniedReason($entity, FALSE);
-    return new AccessResultForbidden($reason);
-  }
-
-  return AccessResult::neutral();
+  return \Drupal::service(EntityReferenceIntegrityEnforceHooks::class)->entityAccess($entity, $operation, $account);
 }
 
 /**
@@ -85,11 +49,7 @@ function entity_reference_integrity_enforce_module_implements_alter(&$implementa
 /**
  * Implements hook_action_info_alter().
  */
+#[LegacyHook]
 function entity_reference_integrity_enforce_action_info_alter(&$definitions) {
-  // Replace the core entity:delete_action plugin.
-  foreach ($definitions as &$definition) {
-    if ($definition['id'] === 'entity:delete_action' && $definition['class'] === CoreDeleteAction::class) {
-      $definition['class'] = DeleteAction::class;
-    }
-  }
+  \Drupal::service(EntityReferenceIntegrityEnforceHooks::class)->actionInfoAlter($definitions);
 }
diff --git a/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.services.yml b/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.services.yml
new file mode 100644
index 0000000..83b5575
--- /dev/null
+++ b/modules/entity_reference_integrity_enforce/entity_reference_integrity_enforce.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\entity_reference_integrity_enforce\Hook\EntityReferenceIntegrityEnforceHooks:
+    class: Drupal\entity_reference_integrity_enforce\Hook\EntityReferenceIntegrityEnforceHooks
+    autowire: true
diff --git a/modules/entity_reference_integrity_enforce/src/Hook/EntityReferenceIntegrityEnforceHooks.php b/modules/entity_reference_integrity_enforce/src/Hook/EntityReferenceIntegrityEnforceHooks.php
new file mode 100644
index 0000000..e01d145
--- /dev/null
+++ b/modules/entity_reference_integrity_enforce/src/Hook/EntityReferenceIntegrityEnforceHooks.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Drupal\entity_reference_integrity_enforce\Hook;
+
+use Drupal\Core\Action\Plugin\Action\DeleteAction;
+use Drupal\Core\Access\AccessResultForbidden;
+use Drupal\entity_reference_integrity\EntityReferenceIntegrityEntityHandler;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\entity_reference_integrity_enforce\EntityPredelete;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\entity_reference_integrity_enforce\FormAlter;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Hook implementations for entity_reference_integrity_enforce.
+ */
+class EntityReferenceIntegrityEnforceHooks {
+
+  /**
+   * Implements hook_form_alter().
+   */
+  #[Hook('form_alter')]
+  public static function formAlter(&$form, FormStateInterface $form_state, $form_id) {
+    \Drupal::service('class_resolver')->getInstanceFromDefinition(FormAlter::class)->formAlter($form, $form_state, $form_id);
+  }
+
+  /**
+   * Implements hook_entity_predelete().
+   */
+  #[Hook('entity_predelete')]
+  public static function entityPredelete(EntityInterface $entity) {
+    \Drupal::service('class_resolver')->getInstanceFromDefinition(EntityPredelete::class)->entityDelete($entity);
+  }
+
+  /**
+   * Implements hook_entity_access().
+   */
+  #[Hook('entity_access')]
+  public static function entityAccess(EntityInterface $entity, $operation, AccountInterface $account) {
+    // Only check access for delete operations.
+    if ($operation != 'delete') {
+      return AccessResult::neutral();
+    }
+    // Only check access for valid routes. This can return NULL.
+    $route = \Drupal::routeMatch()->getRouteObject();
+    if (empty($route)) {
+      return AccessResult::neutral();
+    }
+    // Only check access for API endpoints by checking the route _format.
+    // @todo Check formats for other API endpoints such as GraphQL and REST.
+    $api_formats = [
+      'api_json',
+    ];
+    $format = $route->getRequirement('_format');
+    if (empty($format) || !in_array($format, $api_formats)) {
+      return AccessResult::neutral();
+    }
+    /** @var \Drupal\entity_reference_integrity\EntityReferenceIntegrityEntityHandler $entity_reference_integrity_handler */
+    $entity_reference_integrity_handler = \Drupal::entityTypeManager()->getHandler($entity->getEntityTypeId(), 'entity_reference_integrity');
+    $enabled_entity_type_ids = \Drupal::configFactory()->get('entity_reference_integrity_enforce.settings')->get('enabled_entity_type_ids');
+    // Finally deny access if the entity has dependents.
+    if (in_array($entity->getEntityTypeId(), $enabled_entity_type_ids, TRUE) && $entity_reference_integrity_handler->hasDependents($entity)) {
+      $reason = EntityReferenceIntegrityEntityHandler::getAccessDeniedReason($entity, FALSE);
+      return new AccessResultForbidden($reason);
+    }
+    return AccessResult::neutral();
+  }
+
+  /**
+   * Implements hook_action_info_alter().
+   */
+  #[Hook('action_info_alter')]
+  public static function actionInfoAlter(&$definitions) {
+    // Replace the core entity:delete_action plugin.
+    foreach ($definitions as &$definition) {
+      if ($definition['id'] === 'entity:delete_action' && $definition['class'] === DeleteAction::class) {
+        $definition['class'] = \Drupal\entity_reference_integrity_enforce\Plugin\Action\DeleteAction::class;
+      }
+    }
+  }
+
+}
diff --git a/modules/entity_reference_integrity_enforce/tests/src/Functional/EnforcedIntegrityTest.php b/modules/entity_reference_integrity_enforce/tests/src/Functional/EnforcedIntegrityTest.php
index c9c5025..7862057 100644
--- a/modules/entity_reference_integrity_enforce/tests/src/Functional/EnforcedIntegrityTest.php
+++ b/modules/entity_reference_integrity_enforce/tests/src/Functional/EnforcedIntegrityTest.php
@@ -2,6 +2,10 @@
 
 namespace Drupal\Tests\entity_reference_integrity_enforce\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
+use Drupal\Component\Utility\DeprecationHelper;
+use Drupal\entity_test\EntityTestHelper;
 use Drupal\Core\Entity\EntityStorageException;
 use Drupal\entity_reference_integrity_enforce\Exception\ProtectedEntityException;
 use Drupal\Core\Entity\EntityInterface;
@@ -15,6 +19,8 @@ use Drupal\Tests\BrowserTestBase;
  *
  * @group entity_reference_integrity_enforce
  */
+#[Group('entity_reference_integrity_enforce')]
+#[RunTestsInSeparateProcesses]
 class EnforcedIntegrityTest extends BrowserTestBase {
 
   /**
@@ -128,7 +134,7 @@ class EnforcedIntegrityTest extends BrowserTestBase {
   protected function createDependentEntity(EntityInterface $entity) {
     // Create a bundle with the name name as the target entity type ID and an
     // entity reference field to link the two.
-    entity_test_create_bundle($entity->getEntityTypeId());
+    DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.2.0', fn() => EntityTestHelper::createBundle($entity->getEntityTypeId()), fn() => entity_test_create_bundle($entity->getEntityTypeId()));
     FieldStorageConfig::create([
       'field_name' => 'test_reference_field',
       'entity_type' => 'entity_test',
diff --git a/modules/entity_reference_integrity_enforce/tests/src/Functional/JsonApiTest.php b/modules/entity_reference_integrity_enforce/tests/src/Functional/JsonApiTest.php
index bdc939e..22d3363 100644
--- a/modules/entity_reference_integrity_enforce/tests/src/Functional/JsonApiTest.php
+++ b/modules/entity_reference_integrity_enforce/tests/src/Functional/JsonApiTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\entity_reference_integrity_enforce\Functional;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\Component\Serialization\Json;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Core\Url;
@@ -17,6 +19,8 @@ use GuzzleHttp\RequestOptions;
  *
  * @group entity_reference_integrity_enforce
  */
+#[Group('entity_reference_integrity_enforce')]
+#[RunTestsInSeparateProcesses]
 class JsonApiTest extends BrowserTestBase {
 
   use EntityReferenceFieldCreationTrait;
diff --git a/modules/entity_reference_integrity_enforce/tests/src/Kernel/DeleteActionTest.php b/modules/entity_reference_integrity_enforce/tests/src/Kernel/DeleteActionTest.php
index 54fc4f9..ee79c50 100644
--- a/modules/entity_reference_integrity_enforce/tests/src/Kernel/DeleteActionTest.php
+++ b/modules/entity_reference_integrity_enforce/tests/src/Kernel/DeleteActionTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\entity_reference_integrity_enforce\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\entity_reference_integrity_enforce\Plugin\Action\DeleteAction;
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\node\Entity\Node;
@@ -16,6 +18,8 @@ use Drupal\user\Entity\User;
  *
  * @group entity_reference_integrity_enforce
  */
+#[Group('entity_reference_integrity_enforce')]
+#[RunTestsInSeparateProcesses]
 class DeleteActionTest extends KernelTestBase {
 
   use EntityReferenceFieldCreationTrait;
diff --git a/modules/entity_reference_integrity_enforce/tests/src/Kernel/EntityPredeleteHookTest.php b/modules/entity_reference_integrity_enforce/tests/src/Kernel/EntityPredeleteHookTest.php
index b9590eb..7584a5e 100644
--- a/modules/entity_reference_integrity_enforce/tests/src/Kernel/EntityPredeleteHookTest.php
+++ b/modules/entity_reference_integrity_enforce/tests/src/Kernel/EntityPredeleteHookTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\entity_reference_integrity_enforce\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\KernelTests\KernelTestBase;
 
 /**
@@ -9,6 +11,8 @@ use Drupal\KernelTests\KernelTestBase;
  *
  * @group entity_reference_integrity_enforce
  */
+#[Group('entity_reference_integrity_enforce')]
+#[RunTestsInSeparateProcesses]
 class EntityPredeleteHookTest extends KernelTestBase {
 
   /**
diff --git a/src/Hook/EntityReferenceIntegrityHooks.php b/src/Hook/EntityReferenceIntegrityHooks.php
new file mode 100644
index 0000000..a4f623e
--- /dev/null
+++ b/src/Hook/EntityReferenceIntegrityHooks.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Drupal\entity_reference_integrity\Hook;
+
+use Drupal\entity_reference_integrity\EntityReferenceIntegrityEntityHandler;
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Hook implementations for entity_reference_integrity.
+ */
+class EntityReferenceIntegrityHooks {
+
+  /**
+   * Implements hook_entity_type_alter().
+   */
+  #[Hook('entity_type_alter')]
+  public static function entityTypeAlter(array &$entity_types) {
+    /** @var \Drupal\Core\Entity\EntityTypeInterface $entity_type */
+    foreach ($entity_types as $entity_type) {
+      if (!$entity_type->hasHandlerClass('entity_reference_integrity')) {
+        $entity_type->setHandlerClass('entity_reference_integrity', EntityReferenceIntegrityEntityHandler::class);
+      }
+    }
+  }
+
+}
diff --git a/tests/src/Kernel/EntityReferenceIntegrityEntityHandlerTest.php b/tests/src/Kernel/EntityReferenceIntegrityEntityHandlerTest.php
index 271c8aa..7315b6d 100644
--- a/tests/src/Kernel/EntityReferenceIntegrityEntityHandlerTest.php
+++ b/tests/src/Kernel/EntityReferenceIntegrityEntityHandlerTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\entity_reference_integrity\Kernel;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses;
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\node\Entity\Node;
 use Drupal\user\Entity\User;
@@ -13,6 +15,8 @@ use Drupal\user\Entity\User;
  *
  * @group entity_reference_integrity
  */
+#[Group('entity_reference_integrity')]
+#[RunTestsInSeparateProcesses]
 class EntityReferenceIntegrityEntityHandlerTest extends KernelTestBase {
 
   /**
diff --git a/tests/src/Unit/DependencyFieldMapGeneratorTest.php b/tests/src/Unit/DependencyFieldMapGeneratorTest.php
index c28d6de..67cd3fe 100644
--- a/tests/src/Unit/DependencyFieldMapGeneratorTest.php
+++ b/tests/src/Unit/DependencyFieldMapGeneratorTest.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Tests\entity_reference_integrity\Unit;
 
+use PHPUnit\Framework\Attributes\Group;
+use PHPUnit\Framework\Attributes\DataProvider;
 use Drupal\Core\Entity\ContentEntityTypeInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
@@ -14,6 +16,7 @@ use Drupal\Tests\UnitTestCase;
  *
  * @group entity_reference_integrity
  */
+#[Group('entity_reference_integrity')]
 class DependencyFieldMapGeneratorTest extends UnitTestCase {
 
   /**
@@ -21,6 +24,7 @@ class DependencyFieldMapGeneratorTest extends UnitTestCase {
    *
    * @dataProvider fieldMapTestCases
    */
+  #[DataProvider('fieldMapTestCases')]
   public function testFieldMap($has_custom_storage, $has_storage_definition, $revision_metadata_fields, $field_map, $expected_result) {
 
     $target_entity_type_id = 'target_entity_type_id';
