diff --git a/dynamic_entity_reference.module b/dynamic_entity_reference.module
index 700857f..6a6ed7a 100644
--- a/dynamic_entity_reference.module
+++ b/dynamic_entity_reference.module
@@ -5,9 +5,8 @@
  * Contains main module functionality.
  */
 
-use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
-use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
-use Drupal\field\Entity\FieldConfig;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceHooks;
 use Drupal\field\FieldConfigInterface;
 
 /**
@@ -18,46 +17,9 @@ use Drupal\field\FieldConfigInterface;
  * because we need to take into account bundles that are not provided by a
  * config entity type so they are not part of the config dependencies.
  */
+#[LegacyHook]
 function dynamic_entity_reference_entity_bundle_delete($entity_type_id, $bundle) {
-
-  // Gather a list of all entity reference fields.
-  $map = Drupal::service('entity_field.manager')->getFieldMapByFieldType('dynamic_entity_reference');
-  $ids = [];
-  foreach ($map as $type => $info) {
-    foreach ($info as $name => $data) {
-      foreach ($data['bundles'] as $bundle_name) {
-        $ids[] = "$type.$bundle_name.$name";
-      }
-    }
-  }
-
-  // Update the 'target_bundles' handler setting if needed.
-  foreach (FieldConfig::loadMultiple($ids) as $field_config) {
-    $settings = $field_config->getSettings();
-    $target_types = DynamicEntityReferenceItem::getTargetTypes($settings);
-    if (in_array($entity_type_id, $target_types, TRUE) && isset($settings[$entity_type_id]['handler_settings'])) {
-      $handler_settings = $settings[$entity_type_id]['handler_settings'];
-      if (isset($handler_settings['target_bundles'][$bundle])) {
-        unset($handler_settings['target_bundles'][$bundle]);
-        $settings[$entity_type_id]['handler_settings'] = $handler_settings;
-        $field_config->setSettings($settings);
-        $field_config->save();
-
-        // In case we deleted the only target bundle allowed by the field we
-        // have to log a critical message because the field will not function
-        // correctly anymore.
-        if ($handler_settings['target_bundles'] === []) {
-          \Drupal::logger('dynamic_entity_reference')->critical('The %target_bundle bundle (entity type: %target_entity_type) was deleted. As a result, the %field_name dynamic entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', [
-            '%target_bundle' => $bundle,
-            '%target_entity_type' => $entity_type_id,
-            '%field_name' => $field_config->getName(),
-            '%entity_type' => $field_config->getTargetEntityTypeId(),
-            '%bundle' => $field_config->getTargetBundle(),
-          ]);
-        }
-      }
-    }
-  }
+  \Drupal::service(DynamicEntityReferenceHooks::class)->entityBundleDelete($entity_type_id, $bundle);
 }
 
 /**
@@ -65,31 +27,9 @@ function dynamic_entity_reference_entity_bundle_delete($entity_type_id, $bundle)
  *
  * @todo Clean this up once field_field_config_save is more accommodating.
  */
+#[LegacyHook]
 function dynamic_entity_reference_field_config_presave(FieldConfigInterface $field) {
-  // Don't change anything during a configuration sync.
-  if ($field->isSyncing()) {
-    return;
-  }
-
-  $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
-  $er_item_class = EntityReferenceItem::class;
-  $class = $field_type_manager->getPluginClass($field->getType());
-  if ($class !== $er_item_class && !is_subclass_of($class, $er_item_class)) {
-    return;
-  }
-  $der_item_class = DynamicEntityReferenceItem::class;
-  if ($class === $der_item_class || is_subclass_of($class, $der_item_class)) {
-    // DER needs to be handled differently.
-    return;
-  }
-
-  // Just a normal ER item, do the things field_field_config_presave() would
-  // have done before we removed it in
-  // dynamic_entity_reference_module_implements_alter().
-  $selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
-  $target_type = $field->getFieldStorageDefinition()->getSetting('target_type');
-  [$current_handler] = explode(':', $field->getSetting('handler'), 2);
-  $field->setSetting('handler', $selection_manager->getPluginId($target_type, $current_handler));
+  \Drupal::service(DynamicEntityReferenceHooks::class)->fieldConfigPresave($field);
 }
 
 /**
@@ -109,21 +49,15 @@ function dynamic_entity_reference_module_implements_alter(&$implementations, $ho
 /**
  * Implements hook_form_FORM_ID_alter() for 'field_ui_field_storage_add_form'.
  */
+#[LegacyHook]
 function dynamic_entity_reference_form_field_ui_field_storage_add_form_alter(array &$form) {
-  if (version_compare(\Drupal::VERSION, '10.1.999', '<')) {
-    $optgroup = (string) t('Dynamic entity reference');
-    // Move the "Dynamic entity reference" option to the end of the list and
-    // rename it to "Other".
-    unset($form['add']['new_storage_type']['#options'][$optgroup]['dynamic_entity_reference']);
-    $form['add']['new_storage_type']['#options'][$optgroup]['dynamic_entity_reference'] = t('Other…');
-  }
+  \Drupal::service(DynamicEntityReferenceHooks::class)->formFieldUiFieldStorageAddFormAlter($form);
 }
 
 /**
  * Implements hook_field_info_alter().
  */
+#[LegacyHook]
 function dynamic_entity_reference_field_info_alter(&$info) {
-  if (version_compare(\Drupal::VERSION, '10.1.999', '<')) {
-    $info['dynamic_entity_reference']['category'] = t('Dynamic Reference');
-  }
+  \Drupal::service(DynamicEntityReferenceHooks::class)->fieldInfoAlter($info);
 }
diff --git a/dynamic_entity_reference.services.yml b/dynamic_entity_reference.services.yml
index d00969a..0dd1723 100644
--- a/dynamic_entity_reference.services.yml
+++ b/dynamic_entity_reference.services.yml
@@ -21,3 +21,11 @@ services:
   sqlite.dynamic_entity_reference.storage.create_column:
     class: Drupal\dynamic_entity_reference\Storage\IntColumnHandlerSQLite
     arguments: ['@database']
+
+  Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceHooks:
+    class: Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceHooks
+    autowire: true
+
+  Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceViewsHooks:
+    class: Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceViewsHooks
+    autowire: true
diff --git a/dynamic_entity_reference.views.inc b/dynamic_entity_reference.views.inc
index b199792..0925403 100644
--- a/dynamic_entity_reference.views.inc
+++ b/dynamic_entity_reference.views.inc
@@ -5,128 +5,18 @@
  * Provides views data for the dynamic_entity_reference module.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceViewsHooks;
 use Drupal\Core\Entity\FieldableEntityInterface;
 use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
-use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
 use Drupal\field\FieldStorageConfigInterface;
-use Drupal\Component\Utility\DeprecationHelper;
 
 /**
  * Implements hook_field_views_data().
  */
+#[LegacyHook]
 function dynamic_entity_reference_field_views_data(FieldStorageConfigInterface $field_storage) {
-  // Use the new method if available (Drupal 11.2+), fall back to the deprecated
-  // function while the module still supports Drupal 10.2+.
-  $data = DeprecationHelper::backwardsCompatibleCall(
-    \Drupal::VERSION,
-    '11.2',
-    fn() => \Drupal::service('views.field_data_provider')->defaultFieldImplementation($field_storage),
-    fn() => views_field_default_views_data($field_storage)
-  );
-
-  $entity_manager = \Drupal::entityTypeManager();
-  $labels = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);
-  $options = array_keys($labels[(string) t('Content', [], ['context' => 'Entity type group'])]);
-  $settings = $field_storage->getSettings();
-  // Identify all the target entity type ids that can be referenced.
-  if ($settings['exclude_entity_types']) {
-    $target_entity_type_ids = array_diff($options, $settings['entity_type_ids'] ?: []);
-  }
-  else {
-    $target_entity_type_ids = array_intersect($options, $settings['entity_type_ids'] ?: []);
-  }
-  foreach ($data as $table_name => $table_data) {
-    // Determine if all target entity types have integer ID fields.
-    $all_int_ids = TRUE;
-
-    // Add a relationship to all the target entity types.
-    foreach ($target_entity_type_ids as $target_entity_type_id) {
-      if ($entity_manager->hasHandler($target_entity_type_id, 'views_data')) {
-        $target_entity_type = $entity_manager->getDefinition($target_entity_type_id);
-        $target_entity_id_is_int = DynamicEntityReferenceItem::entityHasIntegerId($target_entity_type_id);
-        $all_int_ids = $all_int_ids && $target_entity_id_is_int;
-        $entity_type_id = $field_storage->getTargetEntityTypeId();
-        $entity_type = $entity_manager->getDefinition($entity_type_id);
-        $target_base_table = $entity_manager->getHandler($target_entity_type_id, 'views_data')
-          ->getViewsTableForEntityType($target_entity_type);
-        $field_name = $field_storage->getName();
-
-        // Provide a relationship for the entity type with the dynamic entity
-        // reference field.
-        $args = [
-          '@label' => $target_entity_type->getLabel(),
-          '@field_name' => $field_name,
-        ];
-        $data[$table_name][$target_entity_type_id . '__' . $field_name]['relationship'] = [
-          'title' => t('@label referenced from @field_name', $args),
-          'label' => t('@field_name: @label', $args),
-          'group' => $entity_type->getLabel(),
-          'help' => t('Appears in: @bundles.', [
-            '@bundles' => implode(', ', $field_storage->getBundles()),
-          ]),
-          'id' => 'standard',
-          'base' => $target_base_table,
-          'entity type' => $target_entity_type_id,
-          'base field' => $target_entity_type->getKey('id'),
-          'relationship field' => $target_entity_id_is_int ? $field_name . '_target_id_int' : $field_name . '_target_id',
-          // Entity reference field only has one target type whereas dynamic
-          // entity reference field can have multiple target types that is why
-          // an extra join condition on target types is needed.
-          'extra' => [
-            [
-              'left_field' => $field_name . '_target_type',
-              'value' => $target_entity_type_id,
-            ],
-          ],
-        ];
-
-        // Provide a reverse relationship for the entity type that is referenced
-        // by the field.
-        $pseudo_field_name = 'reverse__' . $entity_type_id . '__' . $field_name;
-        /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
-        $table_mapping = $entity_manager->getStorage($entity_type_id)
-          ->getTableMapping();
-        $args['@entity'] = $entity_type->getLabel();
-        $args['@label'] = $target_entity_type->getSingularLabel();
-        $data[$target_base_table][$pseudo_field_name]['relationship'] = [
-          'title' => t('@entity using @field_name', $args),
-          'label' => t('@field_name', ['@field_name' => $field_name]),
-          'group' => $target_entity_type->getLabel(),
-          'help' => t('Relate each @entity with a @field_name set to the @label.', $args),
-          'id' => 'entity_reverse',
-          'base' => $entity_manager->getHandler($entity_type_id, 'views_data')
-            ->getViewsTableForEntityType($entity_type),
-          'entity_type' => $entity_type_id,
-          'base field' => $entity_type->getKey('id'),
-          'field_name' => $field_name,
-          'field table' => $table_mapping->getDedicatedDataTableName($field_storage),
-          'field field' => $target_entity_id_is_int ? $field_name . '_target_id_int' : $field_name . '_target_id',
-          // Entity reference field only has one target type whereas dynamic
-          // entity reference field can have multiple target types that is why
-          // an extra join condition on target types is needed.
-          'join_extra' => [
-            [
-              'field' => $field_name . '_target_type',
-              'value' => $target_entity_type_id,
-            ],
-            [
-              'field' => 'deleted',
-              'value' => 0,
-              'numeric' => TRUE,
-            ],
-          ],
-        ];
-      }
-    }
-
-    // If all target IDs are of type integer, update the plugin type to use.
-    if ($all_int_ids) {
-      $data[$table_name][$field_storage->getName() . '_target_id']['argument']['id'] = 'numeric';
-      $data[$table_name][$field_storage->getName() . '_target_id']['filter']['id'] = 'numeric';
-    }
-  }
-
-  return $data;
+  return \Drupal::service(DynamicEntityReferenceViewsHooks::class)->fieldViewsData($field_storage);
 }
 
 /**
@@ -136,130 +26,9 @@ function dynamic_entity_reference_field_views_data(FieldStorageConfigInterface $
  *
  * @todo remove this when https://www.drupal.org/node/2337515 is in.
  */
+#[LegacyHook]
 function dynamic_entity_reference_views_data() {
-  $entity_manager = \Drupal::entityTypeManager();
-
-  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
-  [$entity_types, $sql_entity_types, $fields_all] = dynamic_entity_reference_get_all_base_fields();
-
-  $data = [];
-  foreach ($fields_all as $entity_type_id => $fields) {
-    /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
-    $table_mapping = $entity_manager->getStorage($entity_type_id)->getTableMapping();
-
-    $entity_type = $entity_types[$entity_type_id];
-    $entity_id_is_int = DynamicEntityReferenceItem::entityHasIntegerId($entity_type_id);
-    $base_table = $entity_manager->getHandler($entity_type_id, 'views_data')->getViewsTableForEntityType($entity_type);
-
-    /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
-    foreach ($fields as $field) {
-      $field_name = $field->getName();
-      $columns = $table_mapping->getColumnNames($field_name);
-      $column_id = $entity_id_is_int ? $columns['target_id'] . '_int' : $columns['target_id'];
-      $column_type = $columns['target_type'];
-
-      // Unlimited (-1) or > 1 store field data in a dedicated table.
-      $table = $field->getCardinality() == 1 ? $base_table : $entity_type->getBaseTable() . '__' . $field_name;
-      // Filter out non SQL entity types because \Drupal\views\EntityViewsData
-      // class only allows entities with
-      // \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
-      $targets = array_intersect(DynamicEntityReferenceItem::getTargetTypes($field->getSettings()), array_keys($sql_entity_types));
-      foreach ($targets as $target_entity_type_id) {
-        if ($entity_manager->hasHandler($target_entity_type_id, 'views_data')) {
-          $target_entity_type = $entity_types[$target_entity_type_id];
-          $target_table = $entity_manager->getHandler($target_entity_type_id, 'views_data')
-            ->getViewsTableForEntityType($target_entity_type);
-
-          $t_args = [
-            '@origin_label' => $entity_type->getLabel(),
-            '@target_label' => $target_entity_type->getLabel(),
-            '@field_name' => $field->getLabel() ?: $field_name,
-            '@type' => 'base field',
-          ];
-
-          // Relationship (Origin -> Target).
-          $psuedo_field = $target_entity_type_id . '__' . $field_name;
-          $data[$table][$psuedo_field]['relationship'] = [
-            'title' => t('@field_name to @target_label entities', $t_args),
-            'label' => t('@field_name: @target_label', $t_args),
-            'group' => $entity_type->getLabel(),
-            'help' => t('References to @target_label entities referenced by @field_name @type on @origin_label entities.', $t_args),
-            'id' => 'standard',
-            'base' => $target_table,
-            'entity type' => $target_entity_type_id,
-            'base field' => $target_entity_type->getKey('id'),
-            'relationship field' => $column_id,
-            'extra' => [
-              [
-                // Entity reference field only has one target type whereas
-                // dynamic entity reference field can have multiple target types
-                // that is why extra join condition on target types is needed.
-                'left_field' => $column_type,
-                'value' => $target_entity_type_id,
-              ],
-            ],
-          ];
-
-          // Reverse Relationship (Target -> Origin).
-          $psuedo_field = 'reverse__' . $entity_type_id . '__' . $field_name;
-          $data[$target_table][$psuedo_field]['relationship'] = [
-            'title' => t('Reverse reference to @field_name @type on @origin_label', $t_args),
-            'label' => t('Reverse reference to @field_name @type on @origin_label', $t_args),
-            'group' => $target_entity_type->getLabel(),
-            'help' => t('Reverse reference from @target_label entities referenced by @field_name @type on @origin_label entities.', $t_args),
-          ];
-          // When base field cardinality is 1 then the 'base' and 'field table'
-          // are same because field column(s) exist in entity base table
-          // therefore we can't use entity_reverse relationship plugin.
-          if ($field->getCardinality() == 1) {
-            $data[$target_table][$psuedo_field]['relationship'] += [
-              'id' => 'standard',
-              'base' => $table,
-              'entity type' => $entity_type_id,
-              'base field' => $column_id,
-              'field' => $target_entity_type->getKey('id'),
-              'extra' => [
-                [
-                  // Entity reference field only has one target type whereas
-                  // dynamic entity reference field can have multiple target
-                  // types that is why an extra join condition on target types
-                  // is needed.
-                  'field' => $column_type,
-                  'value' => $target_entity_type_id,
-                ],
-              ],
-            ];
-          }
-          // When base field cardinality is greater then 1 the 'base' and
-          // 'field table' are not same because field column(s) exist in
-          // separate table therefore we have to use entity_reverse relationship
-          // plugin.
-          else {
-            $data[$target_table][$psuedo_field]['relationship'] += [
-              'id' => 'entity_reverse',
-              'base' => $base_table,
-              'entity_type' => $entity_type_id,
-              'base field' => $entity_type->getKey('id'),
-              'field_name' => $field_name,
-              'field table' => $table,
-              'field field' => $column_id,
-              // Entity reference field only has one target type whereas dynamic
-              // entity reference field can have multiple target types that is
-              // why an extra join condition on target types is needed.
-              'join_extra' => [
-                [
-                  'field' => $column_type,
-                  'value' => $target_entity_type_id,
-                ],
-              ],
-            ];
-          }
-        }
-      }
-    }
-  }
-
-  return $data;
+  return \Drupal::service(DynamicEntityReferenceViewsHooks::class)->viewsData();
 }
 
 /**
@@ -267,39 +36,9 @@ function dynamic_entity_reference_views_data() {
  *
  * Changes dynamic_entity_reference base fields argument and filter to numeric.
  */
+#[LegacyHook]
 function dynamic_entity_reference_views_data_alter(&$data) {
-  $entity_manager = \Drupal::entityTypeManager();
-
-  /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
-  [$entity_types, $sql_entity_types, $fields_all] = dynamic_entity_reference_get_all_base_fields();
-
-  foreach ($fields_all as $entity_type_id => $fields) {
-
-    $entity_type = $entity_types[$entity_type_id];
-    $base_table = $entity_manager->getHandler($entity_type_id, 'views_data')->getViewsTableForEntityType($entity_type);
-
-    /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
-    foreach ($fields as $field) {
-      $field_name = $field->getName();
-
-      // Unlimited (-1) or > 1 store field data in a dedicated table.
-      $table = $field->getCardinality() == 1 ? $base_table : $entity_type->getBaseTable() . '__' . $field_name;
-      // Filter out non SQL entity types because \Drupal\views\EntityViewsData
-      // class only allows entities with
-      // \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
-      $targets = array_intersect(DynamicEntityReferenceItem::getTargetTypes($field->getSettings()), array_keys($sql_entity_types));
-      foreach ($targets as $target_entity_type_id) {
-        $target_entity_id_is_int = DynamicEntityReferenceItem::entityHasIntegerId($target_entity_type_id);
-        if ($target_entity_id_is_int) {
-          $data[$table][$target_entity_type_id . '__' . $field_name]['argument']['id'] = 'numeric';
-          $data[$table][$target_entity_type_id . '__' . $field_name]['filter']['id'] = 'numeric';
-        }
-
-      }
-
-    }
-  }
-
+  \Drupal::service(DynamicEntityReferenceViewsHooks::class)->viewsDataAlter($data);
 }
 
 /**
diff --git a/src/Hook/DynamicEntityReferenceHooks.php b/src/Hook/DynamicEntityReferenceHooks.php
new file mode 100644
index 0000000..3cdc31b
--- /dev/null
+++ b/src/Hook/DynamicEntityReferenceHooks.php
@@ -0,0 +1,121 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference\Hook;
+
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\field\FieldConfigInterface;
+use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for dynamic_entity_reference.
+ */
+class DynamicEntityReferenceHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_entity_bundle_delete().
+   *
+   * We are duplicating the work done by
+   * \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem::onDependencyRemoval()
+   * because we need to take into account bundles that are not provided by a
+   * config entity type so they are not part of the config dependencies.
+   */
+  #[Hook('entity_bundle_delete')]
+  public static function entityBundleDelete($entity_type_id, $bundle) {
+    // Gather a list of all entity reference fields.
+    $map = \Drupal::service('entity_field.manager')->getFieldMapByFieldType('dynamic_entity_reference');
+    $ids = [];
+    foreach ($map as $type => $info) {
+      foreach ($info as $name => $data) {
+        foreach ($data['bundles'] as $bundle_name) {
+          $ids[] = "{$type}.{$bundle_name}.{$name}";
+        }
+      }
+    }
+    // Update the 'target_bundles' handler setting if needed.
+    foreach (FieldConfig::loadMultiple($ids) as $field_config) {
+      $settings = $field_config->getSettings();
+      $target_types = DynamicEntityReferenceItem::getTargetTypes($settings);
+      if (in_array($entity_type_id, $target_types, TRUE) && isset($settings[$entity_type_id]['handler_settings'])) {
+        $handler_settings = $settings[$entity_type_id]['handler_settings'];
+        if (isset($handler_settings['target_bundles'][$bundle])) {
+          unset($handler_settings['target_bundles'][$bundle]);
+          $settings[$entity_type_id]['handler_settings'] = $handler_settings;
+          $field_config->setSettings($settings);
+          $field_config->save();
+          // In case we deleted the only target bundle allowed by the field we
+          // have to log a critical message because the field will not function
+          // correctly anymore.
+          if ($handler_settings['target_bundles'] === []) {
+            \Drupal::logger('dynamic_entity_reference')->critical('The %target_bundle bundle (entity type: %target_entity_type) was deleted. As a result, the %field_name dynamic entity reference field (entity_type: %entity_type, bundle: %bundle) no longer has any valid bundle it can reference. The field is not working correctly anymore and has to be adjusted.', [
+              '%target_bundle' => $bundle,
+              '%target_entity_type' => $entity_type_id,
+              '%field_name' => $field_config->getName(),
+              '%entity_type' => $field_config->getTargetEntityTypeId(),
+              '%bundle' => $field_config->getTargetBundle(),
+            ]);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Implements hook_ENTITY_TYPE_presave().
+   *
+   * @todo Clean this up once field_field_config_save is more accommodating.
+   */
+  #[Hook('field_config_presave')]
+  public static function fieldConfigPresave(FieldConfigInterface $field) {
+    // Don't change anything during a configuration sync.
+    if ($field->isSyncing()) {
+      return;
+    }
+    $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
+    $er_item_class = EntityReferenceItem::class;
+    $class = $field_type_manager->getPluginClass($field->getType());
+    if ($class !== $er_item_class && !is_subclass_of($class, $er_item_class)) {
+      return;
+    }
+    $der_item_class = DynamicEntityReferenceItem::class;
+    if ($class === $der_item_class || is_subclass_of($class, $der_item_class)) {
+      // DER needs to be handled differently.
+      return;
+    }
+    // Just a normal ER item, do the things field_field_config_presave() would
+    // have done before we removed it in
+    // dynamic_entity_reference_module_implements_alter().
+    $selection_manager = \Drupal::service('plugin.manager.entity_reference_selection');
+    $target_type = $field->getFieldStorageDefinition()->getSetting('target_type');
+    [$current_handler] = explode(':', $field->getSetting('handler'), 2);
+    $field->setSetting('handler', $selection_manager->getPluginId($target_type, $current_handler));
+  }
+
+  /**
+   * Implements hook_form_FORM_ID_alter() for 'field_ui_field_storage_add_form'.
+   */
+  #[Hook('form_field_ui_field_storage_add_form_alter')]
+  public function formFieldUiFieldStorageAddFormAlter(array &$form) {
+    if (version_compare(\Drupal::VERSION, '10.1.999', '<')) {
+      $optgroup = (string) $this->t('Dynamic entity reference');
+      // Move the "Dynamic entity reference" option to the end of the list and
+      // rename it to "Other".
+      unset($form['add']['new_storage_type']['#options'][$optgroup]['dynamic_entity_reference']);
+      $form['add']['new_storage_type']['#options'][$optgroup]['dynamic_entity_reference'] = $this->t('Other…');
+    }
+  }
+
+  /**
+   * Implements hook_field_info_alter().
+   */
+  #[Hook('field_info_alter')]
+  public function fieldInfoAlter(&$info) {
+    if (version_compare(\Drupal::VERSION, '10.1.999', '<')) {
+      $info['dynamic_entity_reference']['category'] = $this->t('Dynamic Reference');
+    }
+  }
+
+}
diff --git a/src/Hook/DynamicEntityReferenceViewsHooks.php b/src/Hook/DynamicEntityReferenceViewsHooks.php
new file mode 100644
index 0000000..5306728
--- /dev/null
+++ b/src/Hook/DynamicEntityReferenceViewsHooks.php
@@ -0,0 +1,279 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference\Hook;
+
+use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
+use Drupal\Component\Utility\DeprecationHelper;
+use Drupal\field\FieldStorageConfigInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for dynamic_entity_reference.
+ */
+class DynamicEntityReferenceViewsHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_field_views_data().
+   */
+  #[Hook('field_views_data')]
+  public function fieldViewsData(FieldStorageConfigInterface $field_storage) {
+    // Use the new method if available (Drupal 11.2+), fall back to the deprecated
+    // function while the module still supports Drupal 10.2+.
+    $data = DeprecationHelper::backwardsCompatibleCall(\Drupal::VERSION, '11.2', fn() => \Drupal::service('views.field_data_provider')->defaultFieldImplementation($field_storage), fn() => views_field_default_views_data($field_storage));
+    $entity_manager = \Drupal::entityTypeManager();
+    $labels = \Drupal::service('entity_type.repository')->getEntityTypeLabels(TRUE);
+    $options = array_keys($labels[(string) $this->t('Content', [], [
+      'context' => 'Entity type group',
+    ])]);
+    $settings = $field_storage->getSettings();
+    // Identify all the target entity type ids that can be referenced.
+    if ($settings['exclude_entity_types']) {
+      $target_entity_type_ids = array_diff($options, $settings['entity_type_ids'] ?: []);
+    }
+    else {
+      $target_entity_type_ids = array_intersect($options, $settings['entity_type_ids'] ?: []);
+    }
+    foreach ($data as $table_name => $table_data) {
+      // Determine if all target entity types have integer ID fields.
+      $all_int_ids = TRUE;
+      // Add a relationship to all the target entity types.
+      foreach ($target_entity_type_ids as $target_entity_type_id) {
+        if ($entity_manager->hasHandler($target_entity_type_id, 'views_data')) {
+          $target_entity_type = $entity_manager->getDefinition($target_entity_type_id);
+          $target_entity_id_is_int = DynamicEntityReferenceItem::entityHasIntegerId($target_entity_type_id);
+          $all_int_ids = $all_int_ids && $target_entity_id_is_int;
+          $entity_type_id = $field_storage->getTargetEntityTypeId();
+          $entity_type = $entity_manager->getDefinition($entity_type_id);
+          $target_base_table = $entity_manager->getHandler($target_entity_type_id, 'views_data')->getViewsTableForEntityType($target_entity_type);
+          $field_name = $field_storage->getName();
+          // Provide a relationship for the entity type with the dynamic entity
+          // reference field.
+          $args = [
+            '@label' => $target_entity_type->getLabel(),
+            '@field_name' => $field_name,
+          ];
+          $data[$table_name][$target_entity_type_id . '__' . $field_name]['relationship'] = [
+            'title' => $this->t('@label referenced from @field_name', $args),
+            'label' => $this->t('@field_name: @label', $args),
+            'group' => $entity_type->getLabel(),
+            'help' => $this->t('Appears in: @bundles.', [
+              '@bundles' => implode(', ', $field_storage->getBundles()),
+            ]),
+            'id' => 'standard',
+            'base' => $target_base_table,
+            'entity type' => $target_entity_type_id,
+            'base field' => $target_entity_type->getKey('id'),
+            'relationship field' => $target_entity_id_is_int ? $field_name . '_target_id_int' : $field_name . '_target_id',
+                // Entity reference field only has one target type whereas dynamic
+                // entity reference field can have multiple target types that is why
+                // an extra join condition on target types is needed.
+            'extra' => [
+                    [
+                      'left_field' => $field_name . '_target_type',
+                      'value' => $target_entity_type_id,
+                    ],
+            ],
+          ];
+          // Provide a reverse relationship for the entity type that is referenced
+          // by the field.
+          $pseudo_field_name = 'reverse__' . $entity_type_id . '__' . $field_name;
+          /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
+          $table_mapping = $entity_manager->getStorage($entity_type_id)->getTableMapping();
+          $args['@entity'] = $entity_type->getLabel();
+          $args['@label'] = $target_entity_type->getSingularLabel();
+          $data[$target_base_table][$pseudo_field_name]['relationship'] = [
+            'title' => $this->t('@entity using @field_name', $args),
+            'label' => $this->t('@field_name', [
+              '@field_name' => $field_name,
+            ]),
+            'group' => $target_entity_type->getLabel(),
+            'help' => $this->t('Relate each @entity with a @field_name set to the @label.', $args),
+            'id' => 'entity_reverse',
+            'base' => $entity_manager->getHandler($entity_type_id, 'views_data')->getViewsTableForEntityType($entity_type),
+            'entity_type' => $entity_type_id,
+            'base field' => $entity_type->getKey('id'),
+            'field_name' => $field_name,
+            'field table' => $table_mapping->getDedicatedDataTableName($field_storage),
+            'field field' => $target_entity_id_is_int ? $field_name . '_target_id_int' : $field_name . '_target_id',
+                // Entity reference field only has one target type whereas dynamic
+                // entity reference field can have multiple target types that is why
+                // an extra join condition on target types is needed.
+            'join_extra' => [
+                    [
+                      'field' => $field_name . '_target_type',
+                      'value' => $target_entity_type_id,
+                    ],
+                    [
+                      'field' => 'deleted',
+                      'value' => 0,
+                      'numeric' => TRUE,
+                    ],
+            ],
+          ];
+        }
+      }
+      // If all target IDs are of type integer, update the plugin type to use.
+      if ($all_int_ids) {
+        $data[$table_name][$field_storage->getName() . '_target_id']['argument']['id'] = 'numeric';
+        $data[$table_name][$field_storage->getName() . '_target_id']['filter']['id'] = 'numeric';
+      }
+    }
+    return $data;
+  }
+
+  /**
+   * Implements hook_views_data().
+   *
+   * Adds relationships for dynamic_entity_reference base fields.
+   *
+   * @todo remove this when https://www.drupal.org/node/2337515 is in.
+   */
+  #[Hook('views_data')]
+  public function viewsData() {
+    $entity_manager = \Drupal::entityTypeManager();
+    /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
+    [$entity_types, $sql_entity_types, $fields_all] = dynamic_entity_reference_get_all_base_fields();
+    $data = [];
+    foreach ($fields_all as $entity_type_id => $fields) {
+      /** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
+      $table_mapping = $entity_manager->getStorage($entity_type_id)->getTableMapping();
+      $entity_type = $entity_types[$entity_type_id];
+      $entity_id_is_int = DynamicEntityReferenceItem::entityHasIntegerId($entity_type_id);
+      $base_table = $entity_manager->getHandler($entity_type_id, 'views_data')->getViewsTableForEntityType($entity_type);
+      /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
+      foreach ($fields as $field) {
+        $field_name = $field->getName();
+        $columns = $table_mapping->getColumnNames($field_name);
+        $column_id = $entity_id_is_int ? $columns['target_id'] . '_int' : $columns['target_id'];
+        $column_type = $columns['target_type'];
+        // Unlimited (-1) or > 1 store field data in a dedicated table.
+        $table = $field->getCardinality() == 1 ? $base_table : $entity_type->getBaseTable() . '__' . $field_name;
+        // Filter out non SQL entity types because \Drupal\views\EntityViewsData
+        // class only allows entities with
+        // \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
+        $targets = array_intersect(DynamicEntityReferenceItem::getTargetTypes($field->getSettings()), array_keys($sql_entity_types));
+        foreach ($targets as $target_entity_type_id) {
+          if ($entity_manager->hasHandler($target_entity_type_id, 'views_data')) {
+            $target_entity_type = $entity_types[$target_entity_type_id];
+            $target_table = $entity_manager->getHandler($target_entity_type_id, 'views_data')->getViewsTableForEntityType($target_entity_type);
+            $t_args = [
+              '@origin_label' => $entity_type->getLabel(),
+              '@target_label' => $target_entity_type->getLabel(),
+              '@field_name' => $field->getLabel() ?: $field_name,
+              '@type' => 'base field',
+            ];
+            // Relationship (Origin -> Target).
+            $psuedo_field = $target_entity_type_id . '__' . $field_name;
+            $data[$table][$psuedo_field]['relationship'] = [
+              'title' => $this->t('@field_name to @target_label entities', $t_args),
+              'label' => $this->t('@field_name: @target_label', $t_args),
+              'group' => $entity_type->getLabel(),
+              'help' => $this->t('References to @target_label entities referenced by @field_name @type on @origin_label entities.', $t_args),
+              'id' => 'standard',
+              'base' => $target_table,
+              'entity type' => $target_entity_type_id,
+              'base field' => $target_entity_type->getKey('id'),
+              'relationship field' => $column_id,
+              'extra' => [
+                      [
+                          // Entity reference field only has one target type whereas
+                          // dynamic entity reference field can have multiple target types
+                          // that is why extra join condition on target types is needed.
+                        'left_field' => $column_type,
+                        'value' => $target_entity_type_id,
+                      ],
+              ],
+            ];
+            // Reverse Relationship (Target -> Origin).
+            $psuedo_field = 'reverse__' . $entity_type_id . '__' . $field_name;
+            $data[$target_table][$psuedo_field]['relationship'] = [
+              'title' => $this->t('Reverse reference to @field_name @type on @origin_label', $t_args),
+              'label' => $this->t('Reverse reference to @field_name @type on @origin_label', $t_args),
+              'group' => $target_entity_type->getLabel(),
+              'help' => $this->t('Reverse reference from @target_label entities referenced by @field_name @type on @origin_label entities.', $t_args),
+            ];
+            // When base field cardinality is 1 then the 'base' and 'field table'
+            // are same because field column(s) exist in entity base table
+            // therefore we can't use entity_reverse relationship plugin.
+            if ($field->getCardinality() == 1) {
+              $data[$target_table][$psuedo_field]['relationship'] += [
+                'id' => 'standard',
+                'base' => $table,
+                'entity type' => $entity_type_id,
+                'base field' => $column_id,
+                'field' => $target_entity_type->getKey('id'),
+                'extra' => [
+                        [
+                            // Entity reference field only has one target type whereas
+                            // dynamic entity reference field can have multiple target
+                            // types that is why an extra join condition on target types
+                            // is needed.
+                          'field' => $column_type,
+                          'value' => $target_entity_type_id,
+                        ],
+                ],
+              ];
+            }
+            else {
+              $data[$target_table][$psuedo_field]['relationship'] += [
+                'id' => 'entity_reverse',
+                'base' => $base_table,
+                'entity_type' => $entity_type_id,
+                'base field' => $entity_type->getKey('id'),
+                'field_name' => $field_name,
+                'field table' => $table,
+                'field field' => $column_id,
+                    // Entity reference field only has one target type whereas dynamic
+                    // entity reference field can have multiple target types that is
+                    // why an extra join condition on target types is needed.
+                'join_extra' => [
+                        [
+                          'field' => $column_type,
+                          'value' => $target_entity_type_id,
+                        ],
+                ],
+              ];
+            }
+          }
+        }
+      }
+    }
+    return $data;
+  }
+
+  /**
+   * Implements hook_views_data_alter().
+   *
+   * Changes dynamic_entity_reference base fields argument and filter to numeric.
+   */
+  #[Hook('views_data_alter')]
+  public static function viewsDataAlter(&$data) {
+    $entity_manager = \Drupal::entityTypeManager();
+    /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
+    [$entity_types, $sql_entity_types, $fields_all] = dynamic_entity_reference_get_all_base_fields();
+    foreach ($fields_all as $entity_type_id => $fields) {
+      $entity_type = $entity_types[$entity_type_id];
+      $base_table = $entity_manager->getHandler($entity_type_id, 'views_data')->getViewsTableForEntityType($entity_type);
+      /** @var \Drupal\Core\Field\BaseFieldDefinition[] $fields */
+      foreach ($fields as $field) {
+        $field_name = $field->getName();
+        // Unlimited (-1) or > 1 store field data in a dedicated table.
+        $table = $field->getCardinality() == 1 ? $base_table : $entity_type->getBaseTable() . '__' . $field_name;
+        // Filter out non SQL entity types because \Drupal\views\EntityViewsData
+        // class only allows entities with
+        // \Drupal\Core\Entity\Sql\SqlEntityStorageInterface.
+        $targets = array_intersect(DynamicEntityReferenceItem::getTargetTypes($field->getSettings()), array_keys($sql_entity_types));
+        foreach ($targets as $target_entity_type_id) {
+          $target_entity_id_is_int = DynamicEntityReferenceItem::entityHasIntegerId($target_entity_type_id);
+          if ($target_entity_id_is_int) {
+            $data[$table][$target_entity_type_id . '__' . $field_name]['argument']['id'] = 'numeric';
+            $data[$table][$target_entity_type_id . '__' . $field_name]['filter']['id'] = 'numeric';
+          }
+        }
+      }
+    }
+  }
+
+}
diff --git a/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.module b/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.module
index 747e057..1403675 100644
--- a/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.module
+++ b/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.module
@@ -5,286 +5,22 @@
  * Module file for dynamic_entity_reference_entity_test.
  */
 
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\dynamic_entity_reference_entity_test\Hook\DynamicEntityReferenceEntityTestHooks;
 use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Implements hook_entity_base_field_info().
  */
+#[LegacyHook]
 function dynamic_entity_reference_entity_test_entity_base_field_info(EntityTypeInterface $entity_type) {
-  $fields = [];
-  // 'entity_test' with no data table and 'entity_test_mul' is with data table.
-  $test_entities = \Drupal::state()->get('dynamic_entity_reference_entity_test_entities', [
-    'entity_test',
-    'entity_test_mul',
-  ]);
-  $excluded_entity = \Drupal::state()->get('dynamic_entity_reference_entity_test_exclude', []);
-  if (in_array($entity_type->id(), $test_entities)) {
-    $allowed_entities = array_diff($test_entities, $excluded_entity);
-    $settings = [
-      'exclude_entity_types' => FALSE,
-      'entity_type_ids' => array_combine($allowed_entities, $allowed_entities),
-    ];
-    foreach ($test_entities as $entity_type_id) {
-      if (!in_array($entity_type_id, $excluded_entity)) {
-        $settings += [
-          $entity_type_id => [
-            'handler' => "default:$entity_type_id",
-            'handler_settings' => [
-              'target_bundles' => NULL,
-            ],
-          ],
-        ];
-      }
-    }
-    $fields['dynamic_references'] = BaseFieldDefinition::create('dynamic_entity_reference')
-      ->setName('dynamic_references')
-      ->setLabel((string) new TranslatableMarkup('References'))
-      ->setDescription((string) new TranslatableMarkup('Reference another entity.'))
-      ->setRequired(FALSE)
-      ->setRevisionable(\Drupal::state()->get('dynamic_entity_reference_entity_test_revisionable', FALSE))
-      ->setCardinality(\Drupal::state()->get('dynamic_entity_reference_entity_test_cardinality', 1))
-      ->setDisplayOptions('form', [
-        'type' => 'dynamic_entity_reference_default',
-        'weight' => 10,
-      ])
-      ->setDisplayOptions('view', [
-        'label' => 'above',
-        'type' => 'dynamic_entity_reference_label',
-        'weight' => 10,
-      ])
-      ->setDisplayConfigurable('form', TRUE)
-      ->setDisplayConfigurable('view', TRUE)
-      ->setSettings($settings);
-    if (\Drupal::state()->get('dynamic_entity_reference_entity_test_with_two_base_fields', FALSE)) {
-      $fields['der'] = BaseFieldDefinition::createFromFieldStorageDefinition($fields['dynamic_references'])
-        ->setName('der');
-    }
-
-    // Adds a normal entity reference field if set to do so.
-    if (\Drupal::state()->get('dynamic_entity_reference_entity_test_with_normal', FALSE)) {
-      $fields['normal_reference'] = BaseFieldDefinition::create('entity_reference')
-        ->setLabel(t('Entity ID'))
-        ->setDescription(t('The referenced ID of the entity.'))
-        ->setRequired(TRUE);
-    }
-  }
-
-  return $fields;
+  return \Drupal::service(DynamicEntityReferenceEntityTestHooks::class)->entityBaseFieldInfo($entity_type);
 }
 
 /**
  * Implements hook_views_data().
  */
+#[LegacyHook]
 function dynamic_entity_reference_entity_test_views_data() {
-  // @todo Currently views integration for multivalue basefields is broken this
-  //   function adds a temporary fix for that remove this when is fixed
-  //   https://www.drupal.org/node/2477899.
-  $data = [];
-
-  if (\Drupal::state()->get('dynamic_entity_reference_entity_test_cardinality', 1) != 1) {
-    $data['entity_test__dynamic_references'] = [
-      'table' => [
-        'join' => [
-          'entity_test' => [
-            'left_field' => 'id',
-            'field' => 'entity_id',
-          ],
-        ],
-      ],
-      'dynamic_references' => [
-        'group' => "Test entity",
-        'title' => "Test references",
-        'title short' => "Test references",
-        'help' => "Appears in: entity_test.",
-        'field' => [
-          'table' => "entity_test__dynamic_references",
-          'id' => "field",
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-          'real field' => "dynamic_references_type_id",
-          'additional fields' => [
-            "delta",
-            "langcode",
-            "bundle",
-            "dynamic_references_target_id",
-            "dynamic_references_target_type",
-          ],
-          'element type' => "div",
-          'is revision' => FALSE,
-          'click sortable' => TRUE,
-        ],
-      ],
-      'dynamic_references_target_id' => [
-        'group' => "Test entity",
-        'title' => "Test references (dynamic_references)",
-        'title short' => "Test references",
-        'help' => "Appears in: entity_test.",
-        'argument' => [
-          'field' => "dynamic_references_target_id",
-          'table' => "entity_test__dynamic_references",
-          'id' => "numeric",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-          'empty field name' => "- No value -",
-        ],
-        'filter' => [
-          'field' => "dynamic_references_target_id",
-          'table' => "entity_test__dynamic_references",
-          'id' => "numeric",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-          'allow empty' => TRUE,
-        ],
-        'sort' => [
-          'field' => "dynamic_references_target_id",
-          'table' => "entity_test__dynamic_references",
-          'id' => "standard",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-        ],
-      ],
-      'dynamic_references_target_type' => [
-        'group' => "Test entity",
-        'title' => "Test references (dynamic_references:target_type)",
-        'title short' => "Test references:target_type",
-        'help' => "Appears in: entity_test.",
-        'argument' => [
-          'field' => "dynamic_references_target_type",
-          'table' => "entity_test__dynamic_references",
-          'id' => "string",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-          'empty field name' => "- No value -",
-        ],
-        'filter' => [
-          'field' => "dynamic_references_target_type",
-          'table' => "entity_test__dynamic_references",
-          'id' => "string",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-          'allow empty' => TRUE,
-        ],
-        'sort' => [
-          'field' => "dynamic_references_target_type",
-          'table' => "entity_test__dynamic_references",
-          'id' => "standard",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test",
-        ],
-      ],
-    ];
-    $data['entity_test_mul__dynamic_references'] = [
-      'table' => [
-        'join' => [
-          'entity_test_mul_property_data' => [
-            'left_field' => 'id',
-            'field' => 'entity_id',
-            'extra' => [
-              [
-                'left_field' => 'langcode',
-                'field' => 'langcode',
-              ],
-            ],
-          ],
-        ],
-      ],
-      'dynamic_references' => [
-        'group' => "Test entity - data table",
-        'title' => "Test references",
-        'title short' => "Test references",
-        'help' => "Appears in: entity_test_mul.",
-        'field' => [
-          'table' => "entity_test__dynamic_references",
-          'id' => "field",
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-          'real field' => "dynamic_references_type_id",
-          'additional fields' => [
-            "delta",
-            "langcode",
-            "bundle",
-            "dynamic_references_target_id",
-            "dynamic_references_target_type",
-          ],
-          'element type' => "div",
-          'is revision' => FALSE,
-          'click sortable' => TRUE,
-        ],
-      ],
-      'dynamic_references_target_id' => [
-        'group' => "Test entity - data table",
-        'title' => "Test references (dynamic_references)",
-        'title short' => "Test references",
-        'help' => "Appears in: entity_test_mul.",
-        'argument' => [
-          'field' => "dynamic_references_target_id",
-          'table' => "entity_test_mul__dynamic_references",
-          'id' => "numeric",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-          'empty field name' => "- No value -",
-        ],
-        'filter' => [
-          'field' => "dynamic_references_target_id",
-          'table' => "entity_test_mul__dynamic_references",
-          'id' => "numeric",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-          'allow empty' => TRUE,
-        ],
-        'sort' => [
-          'field' => "dynamic_references_target_id",
-          'table' => "entity_test_mul__dynamic_references",
-          'id' => "standard",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-        ],
-      ],
-      'dynamic_references_target_type' => [
-        'group' => "Test entity - data table",
-        'title' => "Test references (dynamic_references:target_type)",
-        'title short' => "Test references:target_type",
-        'help' => "Appears in: entity_test_mul.",
-        'argument' => [
-          'field' => "dynamic_references_target_type",
-          'table' => "entity_test_mul__dynamic_references",
-          'id' => "string",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-          'empty field name' => "- No value -",
-        ],
-        'filter' => [
-          'field' => "dynamic_references_target_type",
-          'table' => "entity_test_mul__dynamic_references",
-          'id' => "string",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-          'allow empty' => TRUE,
-        ],
-        'sort' => [
-          'field' => "dynamic_references_target_type",
-          'table' => "entity_test_mul__dynamic_references",
-          'id' => "standard",
-          'additional fields' => [],
-          'field_name' => "dynamic_references",
-          'entity_type' => "entity_test_mul",
-        ],
-      ],
-    ];
-
-  }
-  return $data;
+  return \Drupal::service(DynamicEntityReferenceEntityTestHooks::class)->viewsData();
 }
diff --git a/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.services.yml b/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.services.yml
new file mode 100644
index 0000000..b681056
--- /dev/null
+++ b/tests/modules/dynamic_entity_reference_entity_test/dynamic_entity_reference_entity_test.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\dynamic_entity_reference_entity_test\Hook\DynamicEntityReferenceEntityTestHooks:
+    class: Drupal\dynamic_entity_reference_entity_test\Hook\DynamicEntityReferenceEntityTestHooks
+    autowire: true
diff --git a/tests/modules/dynamic_entity_reference_entity_test/src/Hook/DynamicEntityReferenceEntityTestHooks.php b/tests/modules/dynamic_entity_reference_entity_test/src/Hook/DynamicEntityReferenceEntityTestHooks.php
new file mode 100644
index 0000000..1dad2c1
--- /dev/null
+++ b/tests/modules/dynamic_entity_reference_entity_test/src/Hook/DynamicEntityReferenceEntityTestHooks.php
@@ -0,0 +1,280 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference_entity_test\Hook;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Hook\Attribute\Hook;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+
+/**
+ * Hook implementations for dynamic_entity_reference_entity_test.
+ */
+class DynamicEntityReferenceEntityTestHooks {
+  use StringTranslationTrait;
+
+  /**
+   * Implements hook_entity_base_field_info().
+   */
+  #[Hook('entity_base_field_info')]
+  public function entityBaseFieldInfo(EntityTypeInterface $entity_type) {
+    $fields = [];
+    // 'entity_test' with no data table and 'entity_test_mul' is with data table.
+    $test_entities = \Drupal::state()->get('dynamic_entity_reference_entity_test_entities', [
+      'entity_test',
+      'entity_test_mul',
+    ]);
+    $excluded_entity = \Drupal::state()->get('dynamic_entity_reference_entity_test_exclude', []);
+    if (in_array($entity_type->id(), $test_entities)) {
+      $allowed_entities = array_diff($test_entities, $excluded_entity);
+      $settings = [
+        'exclude_entity_types' => FALSE,
+        'entity_type_ids' => array_combine($allowed_entities, $allowed_entities),
+      ];
+      foreach ($test_entities as $entity_type_id) {
+        if (!in_array($entity_type_id, $excluded_entity)) {
+          $settings += [
+            $entity_type_id => [
+              'handler' => "default:{$entity_type_id}",
+              'handler_settings' => [
+                'target_bundles' => NULL,
+              ],
+            ],
+          ];
+        }
+      }
+      $fields['dynamic_references'] = BaseFieldDefinition::create('dynamic_entity_reference')->setName('dynamic_references')->setLabel((string) new TranslatableMarkup('References'))->setDescription((string) new TranslatableMarkup('Reference another entity.'))->setRequired(FALSE)->setRevisionable(\Drupal::state()->get('dynamic_entity_reference_entity_test_revisionable', FALSE))->setCardinality(\Drupal::state()->get('dynamic_entity_reference_entity_test_cardinality', 1))->setDisplayOptions('form', [
+        'type' => 'dynamic_entity_reference_default',
+        'weight' => 10,
+      ])->setDisplayOptions('view', [
+        'label' => 'above',
+        'type' => 'dynamic_entity_reference_label',
+        'weight' => 10,
+      ])->setDisplayConfigurable('form', TRUE)->setDisplayConfigurable('view', TRUE)->setSettings($settings);
+      if (\Drupal::state()->get('dynamic_entity_reference_entity_test_with_two_base_fields', FALSE)) {
+        $fields['der'] = BaseFieldDefinition::createFromFieldStorageDefinition($fields['dynamic_references'])->setName('der');
+      }
+      // Adds a normal entity reference field if set to do so.
+      if (\Drupal::state()->get('dynamic_entity_reference_entity_test_with_normal', FALSE)) {
+        $fields['normal_reference'] = BaseFieldDefinition::create('entity_reference')->setLabel($this->t('Entity ID'))->setDescription($this->t('The referenced ID of the entity.'))->setRequired(TRUE);
+      }
+    }
+    return $fields;
+  }
+
+  /**
+   * Implements hook_views_data().
+   */
+  #[Hook('views_data')]
+  public static function viewsData() {
+    // @todo Currently views integration for multivalue basefields is broken this
+    //   function adds a temporary fix for that remove this when is fixed
+    //   https://www.drupal.org/node/2477899.
+    $data = [];
+    if (\Drupal::state()->get('dynamic_entity_reference_entity_test_cardinality', 1) != 1) {
+      $data['entity_test__dynamic_references'] = [
+        'table' => [
+          'join' => [
+            'entity_test' => [
+              'left_field' => 'id',
+              'field' => 'entity_id',
+            ],
+          ],
+        ],
+        'dynamic_references' => [
+          'group' => "Test entity",
+          'title' => "Test references",
+          'title short' => "Test references",
+          'help' => "Appears in: entity_test.",
+          'field' => [
+            'table' => "entity_test__dynamic_references",
+            'id' => "field",
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+            'real field' => "dynamic_references_type_id",
+            'additional fields' => [
+              "delta",
+              "langcode",
+              "bundle",
+              "dynamic_references_target_id",
+              "dynamic_references_target_type",
+            ],
+            'element type' => "div",
+            'is revision' => FALSE,
+            'click sortable' => TRUE,
+          ],
+        ],
+        'dynamic_references_target_id' => [
+          'group' => "Test entity",
+          'title' => "Test references (dynamic_references)",
+          'title short' => "Test references",
+          'help' => "Appears in: entity_test.",
+          'argument' => [
+            'field' => "dynamic_references_target_id",
+            'table' => "entity_test__dynamic_references",
+            'id' => "numeric",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+            'empty field name' => "- No value -",
+          ],
+          'filter' => [
+            'field' => "dynamic_references_target_id",
+            'table' => "entity_test__dynamic_references",
+            'id' => "numeric",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+            'allow empty' => TRUE,
+          ],
+          'sort' => [
+            'field' => "dynamic_references_target_id",
+            'table' => "entity_test__dynamic_references",
+            'id' => "standard",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+          ],
+        ],
+        'dynamic_references_target_type' => [
+          'group' => "Test entity",
+          'title' => "Test references (dynamic_references:target_type)",
+          'title short' => "Test references:target_type",
+          'help' => "Appears in: entity_test.",
+          'argument' => [
+            'field' => "dynamic_references_target_type",
+            'table' => "entity_test__dynamic_references",
+            'id' => "string",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+            'empty field name' => "- No value -",
+          ],
+          'filter' => [
+            'field' => "dynamic_references_target_type",
+            'table' => "entity_test__dynamic_references",
+            'id' => "string",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+            'allow empty' => TRUE,
+          ],
+          'sort' => [
+            'field' => "dynamic_references_target_type",
+            'table' => "entity_test__dynamic_references",
+            'id' => "standard",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test",
+          ],
+        ],
+      ];
+      $data['entity_test_mul__dynamic_references'] = [
+        'table' => [
+          'join' => [
+            'entity_test_mul_property_data' => [
+              'left_field' => 'id',
+              'field' => 'entity_id',
+              'extra' => [
+                            [
+                              'left_field' => 'langcode',
+                              'field' => 'langcode',
+                            ],
+              ],
+            ],
+          ],
+        ],
+        'dynamic_references' => [
+          'group' => "Test entity - data table",
+          'title' => "Test references",
+          'title short' => "Test references",
+          'help' => "Appears in: entity_test_mul.",
+          'field' => [
+            'table' => "entity_test__dynamic_references",
+            'id' => "field",
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+            'real field' => "dynamic_references_type_id",
+            'additional fields' => [
+              "delta",
+              "langcode",
+              "bundle",
+              "dynamic_references_target_id",
+              "dynamic_references_target_type",
+            ],
+            'element type' => "div",
+            'is revision' => FALSE,
+            'click sortable' => TRUE,
+          ],
+        ],
+        'dynamic_references_target_id' => [
+          'group' => "Test entity - data table",
+          'title' => "Test references (dynamic_references)",
+          'title short' => "Test references",
+          'help' => "Appears in: entity_test_mul.",
+          'argument' => [
+            'field' => "dynamic_references_target_id",
+            'table' => "entity_test_mul__dynamic_references",
+            'id' => "numeric",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+            'empty field name' => "- No value -",
+          ],
+          'filter' => [
+            'field' => "dynamic_references_target_id",
+            'table' => "entity_test_mul__dynamic_references",
+            'id' => "numeric",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+            'allow empty' => TRUE,
+          ],
+          'sort' => [
+            'field' => "dynamic_references_target_id",
+            'table' => "entity_test_mul__dynamic_references",
+            'id' => "standard",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+          ],
+        ],
+        'dynamic_references_target_type' => [
+          'group' => "Test entity - data table",
+          'title' => "Test references (dynamic_references:target_type)",
+          'title short' => "Test references:target_type",
+          'help' => "Appears in: entity_test_mul.",
+          'argument' => [
+            'field' => "dynamic_references_target_type",
+            'table' => "entity_test_mul__dynamic_references",
+            'id' => "string",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+            'empty field name' => "- No value -",
+          ],
+          'filter' => [
+            'field' => "dynamic_references_target_type",
+            'table' => "entity_test_mul__dynamic_references",
+            'id' => "string",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+            'allow empty' => TRUE,
+          ],
+          'sort' => [
+            'field' => "dynamic_references_target_type",
+            'table' => "entity_test_mul__dynamic_references",
+            'id' => "standard",
+            'additional fields' => [],
+            'field_name' => "dynamic_references",
+            'entity_type' => "entity_test_mul",
+          ],
+        ],
+      ];
+    }
+    return $data;
+  }
+
+}
diff --git a/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.module b/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.module
index fe8c08c..6bf8d49 100644
--- a/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.module
+++ b/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.module
@@ -5,14 +5,13 @@
  * Module file for dynamic_entity_reference_test_views.
  */
 
-use Drupal\entity_test\EntityTestViewsData;
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\dynamic_entity_reference_test_views\Hook\DynamicEntityReferenceTestViewsHooks;
 
 /**
  * Implements hook_entity_type_alter().
  */
+#[LegacyHook]
 function dynamic_entity_reference_test_views_entity_type_alter(array &$entity_types) {
-  if (\Drupal::state()->get('dynamic_entity_reference_test_views.entity_test_string_id.view', FALSE)) {
-    // Integrate with Views.
-    $entity_types['entity_test_string_id']->setHandlerClass('views_data', EntityTestViewsData::class);
-  }
+  \Drupal::service(DynamicEntityReferenceTestViewsHooks::class)->entityTypeAlter($entity_types);
 }
diff --git a/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.services.yml b/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.services.yml
new file mode 100644
index 0000000..1c56712
--- /dev/null
+++ b/tests/modules/dynamic_entity_reference_test_views/dynamic_entity_reference_test_views.services.yml
@@ -0,0 +1,5 @@
+
+services:
+  Drupal\dynamic_entity_reference_test_views\Hook\DynamicEntityReferenceTestViewsHooks:
+    class: Drupal\dynamic_entity_reference_test_views\Hook\DynamicEntityReferenceTestViewsHooks
+    autowire: true
diff --git a/tests/modules/dynamic_entity_reference_test_views/src/Hook/DynamicEntityReferenceTestViewsHooks.php b/tests/modules/dynamic_entity_reference_test_views/src/Hook/DynamicEntityReferenceTestViewsHooks.php
new file mode 100644
index 0000000..e2085ec
--- /dev/null
+++ b/tests/modules/dynamic_entity_reference_test_views/src/Hook/DynamicEntityReferenceTestViewsHooks.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference_test_views\Hook;
+
+use Drupal\entity_test\EntityTestViewsData;
+use Drupal\Core\Hook\Attribute\Hook;
+
+/**
+ * Hook implementations for dynamic_entity_reference_test_views.
+ */
+class DynamicEntityReferenceTestViewsHooks {
+
+  /**
+   * Implements hook_entity_type_alter().
+   */
+  #[Hook('entity_type_alter')]
+  public static function entityTypeAlter(array &$entity_types) {
+    if (\Drupal::state()->get('dynamic_entity_reference_test_views.entity_test_string_id.view', FALSE)) {
+      // Integrate with Views.
+      $entity_types['entity_test_string_id']->setHandlerClass('views_data', EntityTestViewsData::class);
+    }
+  }
+
+}
diff --git a/tests/src/Functional/Update/DerRevUpdateTest.php b/tests/src/Functional/Update/DerRevUpdateTest.php
index c198f1b..8ec5148 100644
--- a/tests/src/Functional/Update/DerRevUpdateTest.php
+++ b/tests/src/Functional/Update/DerRevUpdateTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\dynamic_entity_reference\Functional\Update;
 
+use PHPUnit\Framework\Attributes\IgnoreDeprecations;
 use Drupal\entity_test\Entity\EntityTestMulRev;
 use Drupal\entity_test\Entity\EntityTestRev;
 use Drupal\entity_test\Entity\EntityTestStringId;
@@ -11,8 +12,8 @@ use Drupal\FunctionalTests\Update\UpdatePathTestBase;
  * Tests the revisionable DER fields update path.
  *
  * @group dynamic_entity_reference
- * @group legacy
  */
+#[IgnoreDeprecations]
 class DerRevUpdateTest extends UpdatePathTestBase {
 
   /**
diff --git a/tests/src/Functional/Update/DerUpdate8202Test.php b/tests/src/Functional/Update/DerUpdate8202Test.php
index 49808fa..569a35c 100644
--- a/tests/src/Functional/Update/DerUpdate8202Test.php
+++ b/tests/src/Functional/Update/DerUpdate8202Test.php
@@ -2,14 +2,15 @@
 
 namespace Drupal\Tests\dynamic_entity_reference\Functional\Update;
 
+use PHPUnit\Framework\Attributes\IgnoreDeprecations;
 use Drupal\FunctionalTests\Update\UpdatePathTestBase;
 
 /**
  * Tests DER update path from 8201 and on.
  *
  * @group dynamic_entity_reference
- * @group legacy
  */
+#[IgnoreDeprecations]
 class DerUpdate8202Test extends UpdatePathTestBase {
 
   /**
diff --git a/tests/src/Functional/Update/DerUpdateTest.php b/tests/src/Functional/Update/DerUpdateTest.php
index 3959ae3..8e6a44e 100644
--- a/tests/src/Functional/Update/DerUpdateTest.php
+++ b/tests/src/Functional/Update/DerUpdateTest.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\Tests\dynamic_entity_reference\Functional\Update;
 
+use PHPUnit\Framework\Attributes\IgnoreDeprecations;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\entity_test\Entity\EntityTestMul;
 use Drupal\entity_test\Entity\EntityTestStringId;
@@ -11,8 +12,8 @@ use Drupal\FunctionalTests\Update\UpdatePathTestBase;
  * Tests DER update path.
  *
  * @group dynamic_entity_reference
- * @group legacy
  */
+#[IgnoreDeprecations]
 class DerUpdateTest extends UpdatePathTestBase {
 
   /**
diff --git a/tests/src/Kernel/EntityQueryRelationshipTest.php b/tests/src/Kernel/EntityQueryRelationshipTest.php
index 1733966..9629548 100644
--- a/tests/src/Kernel/EntityQueryRelationshipTest.php
+++ b/tests/src/Kernel/EntityQueryRelationshipTest.php
@@ -220,7 +220,6 @@ class EntityQueryRelationshipTest extends EntityKernelTestBase {
     // @todo Is there a better way than reflection?
     $reflection = new \ReflectionObject($query);
     $property = $reflection->getProperty('sqlQuery');
-    $property->setAccessible(TRUE);
     $sql = (string) $property->getValue($query);
     if ($integer_column) {
       $this->assertTrue(strpos($sql, "[{$field_name}_target_id_int] AND ") !== FALSE, 'Query joined on target_id_int column.');
