diff --git a/dynamic_entity_reference.module b/dynamic_entity_reference.module
index 700857f..c1e1f76 100644
--- a/dynamic_entity_reference.module
+++ b/dynamic_entity_reference.module
@@ -4,7 +4,8 @@
  * @file
  * Contains main module functionality.
  */
-
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\dynamic_entity_reference\Hook\DynamicEntityReferenceHooks;
 use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
 use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
 use Drupal\field\Entity\FieldConfig;
@@ -18,46 +19,10 @@ 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.
  */
-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(),
-          ]);
-        }
-      }
-    }
-  }
+#[LegacyHook]
+function dynamic_entity_reference_entity_bundle_delete($entity_type_id, $bundle)
+{
+    \Drupal::service(DynamicEntityReferenceHooks::class)->entityBundleDelete($entity_type_id, $bundle);
 }
 
 /**
@@ -65,31 +30,10 @@ function dynamic_entity_reference_entity_bundle_delete($entity_type_id, $bundle)
  *
  * @todo Clean this up once field_field_config_save is more accommodating.
  */
-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));
+#[LegacyHook]
+function dynamic_entity_reference_field_config_presave(FieldConfigInterface $field)
+{
+    \Drupal::service(DynamicEntityReferenceHooks::class)->fieldConfigPresave($field);
 }
 
 /**
@@ -109,21 +53,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..bd5a9cd 100644
--- a/dynamic_entity_reference.views.inc
+++ b/dynamic_entity_reference.views.inc
@@ -4,7 +4,8 @@
  * @file
  * 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;
@@ -14,119 +15,10 @@ use Drupal\Component\Utility\DeprecationHelper;
 /**
  * Implements hook_field_views_data().
  */
-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;
+#[LegacyHook]
+function dynamic_entity_reference_field_views_data(FieldStorageConfigInterface $field_storage)
+{
+    return \Drupal::service(DynamicEntityReferenceViewsHooks::class)->fieldViewsData($field_storage);
 }
 
 /**
@@ -136,130 +28,10 @@ function dynamic_entity_reference_field_views_data(FieldStorageConfigInterface $
  *
  * @todo remove this when https://www.drupal.org/node/2337515 is in.
  */
-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;
+#[LegacyHook]
+function dynamic_entity_reference_views_data()
+{
+    return \Drupal::service(DynamicEntityReferenceViewsHooks::class)->viewsData();
 }
 
 /**
@@ -267,39 +39,10 @@ function dynamic_entity_reference_views_data() {
  *
  * Changes dynamic_entity_reference base fields argument and filter to numeric.
  */
-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';
-        }
-
-      }
-
-    }
-  }
-
+#[LegacyHook]
+function dynamic_entity_reference_views_data_alter(&$data)
+{
+    \Drupal::service(DynamicEntityReferenceViewsHooks::class)->viewsDataAlter($data);
 }
 
 /**
diff --git a/src/Hook/DynamicEntityReferenceHooks.php b/src/Hook/DynamicEntityReferenceHooks.php
new file mode 100644
index 0000000..b199dc6
--- /dev/null
+++ b/src/Hook/DynamicEntityReferenceHooks.php
@@ -0,0 +1,122 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference\Hook;
+
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\field\FieldConfigInterface;
+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 (\Drupal\field\Entity\FieldConfig::loadMultiple($ids) as $field_config) {
+            $settings = $field_config->getSettings();
+            $target_types = \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\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(\Drupal\field\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 = \Drupal\Core\Field\Plugin\Field\FieldType\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 = \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\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..79c270c
--- /dev/null
+++ b/src/Hook/DynamicEntityReferenceViewsHooks.php
@@ -0,0 +1,282 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference\Hook;
+
+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;
+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(\Drupal\field\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 = \Drupal\Component\Utility\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 = \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\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 = \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\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(\Drupal\dynamic_entity_reference\Plugin\Field\FieldType\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(\Drupal\dynamic_entity_reference\Plugin\Field\FieldType\DynamicEntityReferenceItem::getTargetTypes($field->getSettings()), array_keys($sql_entity_types));
+                foreach ($targets as $target_entity_type_id) {
+                    $target_entity_id_is_int = \Drupal\dynamic_entity_reference\Plugin\Field\FieldType\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..ea8666b 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
@@ -4,7 +4,8 @@
  * @file
  * 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;
@@ -12,279 +13,17 @@ use Drupal\Core\StringTranslation\TranslatableMarkup;
 /**
  * Implements hook_entity_base_field_info().
  */
-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;
+#[LegacyHook]
+function dynamic_entity_reference_entity_test_entity_base_field_info(EntityTypeInterface $entity_type)
+{
+    return \Drupal::service(DynamicEntityReferenceEntityTestHooks::class)->entityBaseFieldInfo($entity_type);
 }
 
 /**
  * Implements hook_views_data().
  */
-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;
+#[LegacyHook]
+function dynamic_entity_reference_entity_test_views_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..677cb02
--- /dev/null
+++ b/tests/modules/dynamic_entity_reference_entity_test/src/Hook/DynamicEntityReferenceEntityTestHooks.php
@@ -0,0 +1,294 @@
+<?php
+
+namespace Drupal\dynamic_entity_reference_entity_test\Hook;
+
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+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(\Drupal\Core\Entity\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'] = \Drupal\Core\Field\BaseFieldDefinition::create('dynamic_entity_reference')->setName('dynamic_references')->setLabel((string) new \Drupal\Core\StringTranslation\TranslatableMarkup('References'))->setDescription((string) new \Drupal\Core\StringTranslation\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'] = \Drupal\Core\Field\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'] = \Drupal\Core\Field\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..4647d8f 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
@@ -4,15 +4,14 @@
  * @file
  * Module file for dynamic_entity_reference_test_views.
  */
-
+use Drupal\Core\Hook\Attribute\LegacyHook;
+use Drupal\dynamic_entity_reference_test_views\Hook\DynamicEntityReferenceTestViewsHooks;
 use Drupal\entity_test\EntityTestViewsData;
 
 /**
  * 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..1267c9d
--- /dev/null
+++ b/tests/modules/dynamic_entity_reference_test_views/src/Hook/DynamicEntityReferenceTestViewsHooks.php
@@ -0,0 +1,23 @@
+<?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', \Drupal\entity_test\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 {
 
   /**
