diff --git a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
index 6a4e2cdc98a9f76802f3ae505d814a03cbd8a508..dfc6f71a7a1c7cc412a84fb4746c9c51d0f9f1a8 100644
--- a/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
+++ b/core/lib/Drupal/Core/Config/Entity/ConfigEntityType.php
@@ -62,8 +62,8 @@ class ConfigEntityType extends EntityType implements ConfigEntityTypeInterface {
   public function __construct($definition) {
     // Ensure a default list cache tag is set; do this before calling the parent
     // constructor, because we want "Configuration System style" cache tags.
-    if (empty($this->list_cache_tags)) {
-      $this->list_cache_tags = ['config:' . $definition['id'] . '_list'];
+    if (empty($definition['list_cache_tags'])) {
+      $definition['list_cache_tags'] = ['config:' . $definition['id'] . '_list'];
     }
 
     parent::__construct($definition);
diff --git a/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php b/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
index e6c401afa9b0fa3266cb4b0a25cbd91630158149..33668a115dc7d6120bdc745c554697e51b64c34b 100644
--- a/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
+++ b/core/lib/Drupal/Core/Datetime/Entity/DateFormat.php
@@ -2,33 +2,32 @@
 
 namespace Drupal\Core\Datetime\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Datetime\DateFormatInterface;
+use Drupal\system\DateFormatAccessControlHandler;
 
 /**
  * Defines the Date Format configuration entity class.
- *
- * @ConfigEntityType(
- *   id = "date_format",
- *   label = @Translation("Date format"),
- *   handlers = {
- *     "access" = "Drupal\system\DateFormatAccessControlHandler",
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   admin_permission = "administer site configuration",
- *   list_cache_tags = { "rendered" },
- *   config_export = {
- *     "id",
- *     "label",
- *     "locked",
- *     "pattern",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'date_format',
+  label: new TranslatableMarkup('Date format'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: ['access' => DateFormatAccessControlHandler::class],
+  admin_permission: 'administer site configuration',
+  list_cache_tags: ['rendered'],
+  config_export: [
+    'id',
+    'label',
+    'locked',
+    'pattern',
+  ])]
 class DateFormat extends ConfigEntityBase implements DateFormatInterface {
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Attribute/ConfigEntityType.php b/core/lib/Drupal/Core/Entity/Attribute/ConfigEntityType.php
new file mode 100644
index 0000000000000000000000000000000000000000..a784f1248ac0e1402af66f2c546310cb0d1d6898
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Attribute/ConfigEntityType.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\Core\Entity\Attribute;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines a configuration entity type attribute object.
+ *
+ * Configuration entity type plugins use an object-based attribute method. The
+ * attribute properties of configuration entity types are found on
+ * \Drupal\Core\Config\Entity\ConfigEntityType and are accessed using get/set
+ * methods defined in \Drupal\Core\Entity\EntityTypeInterface.
+ *
+ * @ingroup entity_api
+ *
+ * @see \Drupal\Core\Entity\EntityType
+ * @see \Drupal\Core\Config\Entity\ConfigEntityType
+ * @see \Drupal\Core\Config\Entity\ConfigEntityTypeInterface
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class ConfigEntityType extends EntityType {
+
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $label = NULL,
+    public readonly ?TranslatableMarkup $label_collection = NULL,
+    public readonly ?TranslatableMarkup $label_singular = NULL,
+    public readonly ?TranslatableMarkup $label_plural = NULL,
+    public readonly ?string $config_prefix = NULL,
+    public readonly string $entity_type_class = 'Drupal\Core\Config\Entity\ConfigEntityType',
+    public readonly string $group = 'configuration',
+    public readonly TranslatableMarkup $group_label = new TranslatableMarkup('Configuration', [], ['context' => 'Entity type group']),
+    public readonly bool $static_cache = FALSE,
+    public readonly bool $persistent_cache = TRUE,
+    protected readonly array $entity_keys = [],
+    protected readonly array $handlers = [],
+    protected readonly array $links = [],
+    public readonly ?string $admin_permission = NULL,
+    public readonly ?string $collection_permission = NULL,
+    public readonly string $permission_granularity = 'entity_type',
+    public readonly ?string $bundle_of = NULL,
+    public readonly ?TranslatableMarkup $bundle_label = NULL,
+    public readonly bool $internal = FALSE,
+    public readonly array $label_count = [],
+    public readonly ?string $uri_callback = NULL,
+    public readonly bool $common_reference_target = FALSE,
+    public readonly array $list_cache_contexts = [],
+    public readonly array $list_cache_tags = [],
+    public readonly array $constraints = [],
+    public readonly array $additional = [],
+    public readonly array $lookup_keys = [],
+    public readonly array $config_export = [],
+  ) {
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Attribute/ContentEntityType.php b/core/lib/Drupal/Core/Entity/Attribute/ContentEntityType.php
new file mode 100644
index 0000000000000000000000000000000000000000..285607bc5e34e4f2addf3d671a4809243f58949a
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Attribute/ContentEntityType.php
@@ -0,0 +1,65 @@
+<?php
+
+namespace Drupal\Core\Entity\Attribute;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines a content entity type for plugin discovery.
+ *
+ * Content entity type plugins use an object-based attribute method, rather
+ * than an array-type (as commonly used on other plugin types). The attribute
+ * properties of content entity types are found on
+ * \Drupal\Core\Entity\ContentEntityType and are accessed using get/set methods
+ * defined in \Drupal\Core\Entity\ContentEntityTypeInterface.
+ *
+ * @ingroup entity_api
+ *
+ * @see \Drupal\Core\Entity\EntityType
+ * @see \Drupal\Core\Entity\ContentEntityType
+ * @see \Drupal\Core\Entity\ContentEntityTypeInterface
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class ContentEntityType extends EntityType {
+
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $label = NULL,
+    public readonly ?TranslatableMarkup $label_collection = NULL,
+    public readonly ?TranslatableMarkup $label_singular = NULL,
+    public readonly ?TranslatableMarkup $label_plural = NULL,
+    public readonly string $entity_type_class = 'Drupal\Core\Entity\ContentEntityType',
+    public readonly string $group = 'content',
+    public readonly TranslatableMarkup $group_label = new TranslatableMarkup('Content', [], ['context' => 'Entity type group']),
+    public readonly bool $static_cache = TRUE,
+    public readonly bool $render_cache = TRUE,
+    public readonly bool $persistent_cache = TRUE,
+    protected readonly array $entity_keys = [],
+    protected readonly array $handlers = [],
+    protected readonly array $links = [],
+    public readonly ?string $admin_permission = NULL,
+    public readonly ?string $collection_permission = NULL,
+    public readonly string $permission_granularity = 'entity_type',
+    public readonly ?string $bundle_entity_type = NULL,
+    public readonly ?string $bundle_of = NULL,
+    public readonly ?TranslatableMarkup $bundle_label = NULL,
+    public readonly ?string $base_table = NULL,
+    public readonly ?string $data_table = NULL,
+    public readonly ?string $revision_table = NULL,
+    public readonly ?string $revision_data_table = NULL,
+    public readonly bool $internal = FALSE,
+    public readonly bool $translatable = FALSE,
+    public readonly bool $show_revision_ui = FALSE,
+    public readonly array $label_count = [],
+    public readonly ?string $uri_callback = NULL,
+    public readonly ?string $field_ui_base_route = NULL,
+    public readonly bool $common_reference_target = FALSE,
+    public readonly array $list_cache_contexts = [],
+    public readonly array $list_cache_tags = [],
+    public readonly array $constraints = [],
+    public readonly array $revision_metadata_keys = [],
+    public readonly array $additional = [],
+  ) {
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Attribute/EntityType.php b/core/lib/Drupal/Core/Entity/Attribute/EntityType.php
new file mode 100644
index 0000000000000000000000000000000000000000..40d769e61c0289709b6bd0f2197cdcd330cb0a82
--- /dev/null
+++ b/core/lib/Drupal/Core/Entity/Attribute/EntityType.php
@@ -0,0 +1,81 @@
+<?php
+
+namespace Drupal\Core\Entity\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines an entity type for plugin discovery.
+ *
+ * Entity type plugins use an object-based attribute method. The attribute
+ * properties of entity types are found on \Drupal\Core\Entity\EntityType and
+ * are accessed using get/set methods defined in
+ * \Drupal\Core\Entity\EntityTypeInterface.
+ *
+ * @ingroup entity_api
+ *
+ * @see \Drupal\Core\Entity\EntityType
+ * @see \Drupal\Core\Entity\ContentEntityTypeInterface
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class EntityType extends Plugin {
+
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $label = NULL,
+    public readonly ?TranslatableMarkup $label_collection = NULL,
+    public readonly ?TranslatableMarkup $label_singular = NULL,
+    public readonly ?TranslatableMarkup $label_plural = NULL,
+    public readonly string $entity_type_class = 'Drupal\Core\Entity\EntityType',
+    public readonly string $group = 'default',
+    public readonly TranslatableMarkup $group_label = new TranslatableMarkup('Other', [], ['context' => 'Entity type group']),
+    public readonly bool $static_cache = TRUE,
+    public readonly bool $render_cache = TRUE,
+    public readonly bool $persistent_cache = TRUE,
+    protected readonly array $entity_keys = [],
+    protected readonly array $handlers = [],
+    protected readonly array $links = [],
+    public readonly ?string $admin_permission = NULL,
+    public readonly ?string $collection_permission = NULL,
+    public readonly string $permission_granularity = 'entity_type',
+    public readonly ?string $bundle_entity_type = NULL,
+    public readonly ?string $bundle_of = NULL,
+    public readonly ?TranslatableMarkup $bundle_label = NULL,
+    public readonly ?string $base_table = NULL,
+    public readonly ?string $data_table = NULL,
+    public readonly ?string $revision_table = NULL,
+    public readonly ?string $revision_data_table = NULL,
+    public readonly bool $internal = FALSE,
+    public readonly bool $translatable = FALSE,
+    public readonly bool $show_revision_ui = FALSE,
+    public readonly array $label_count = [],
+    public readonly ?string $uri_callback = NULL,
+    public readonly ?string $field_ui_base_route = NULL,
+    public readonly bool $common_reference_target = FALSE,
+    public readonly array $list_cache_contexts = [],
+    public readonly array $list_cache_tags = [],
+    public readonly array $constraints = [],
+    public readonly array $additional = [],
+  ) {
+
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function get(): array|object {
+    // Use the specified entity type class, and remove it before instantiating.
+    $class = $this->entity_type_class;
+
+    $values = array_filter(get_object_vars($this) + [
+      'class' => $this->getClass(),
+      'provider' => $this->getProvider(),
+    ], function ($value, $key) {
+      return !($value === NULL && ($key === 'deriver' || $key === 'provider' || $key == 'entity_type_class'));
+    }, ARRAY_FILTER_USE_BOTH);
+
+    return new $class($values);
+  }
+
+}
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
index c292c53ff6b2bf699b05dc9977be8fad5c81d62b..0ee6cb9c88e8f22c51edd253ede7f2fb6050dc72 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormDisplay.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\Core\Entity\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\Entity\Access\EntityFormDisplayAccessControlHandler;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityConstraintViolationListInterface;
 use Drupal\Core\Entity\EntityDisplayPluginCollection;
 use Drupal\Core\Entity\FieldableEntityInterface;
@@ -17,30 +20,33 @@
  *
  * Contains widget options for all components of an entity form in a given
  * form mode.
- *
- * @ConfigEntityType(
- *   id = "entity_form_display",
- *   label = @Translation("Entity form display"),
- *   entity_keys = {
- *     "id" = "id",
- *     "status" = "status"
- *   },
- *   handlers = {
- *     "access" = "\Drupal\Core\Entity\Entity\Access\EntityFormDisplayAccessControlHandler",
- *   },
- *   config_export = {
- *     "id",
- *     "targetEntityType",
- *     "bundle",
- *     "mode",
- *     "content",
- *     "hidden",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "targetEntityType", "bundle", "mode"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'entity_form_display',
+  label: new TranslatableMarkup('Entity form display'),
+  entity_keys: [
+    'id' => 'id',
+    'status' => 'status',
+  ],
+  handlers: [
+    'access' => EntityFormDisplayAccessControlHandler::class,
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'targetEntityType',
+      'bundle',
+      'mode',
+    ],
+  ],
+  config_export: [
+    'id',
+    'targetEntityType',
+    'bundle',
+    'mode',
+    'content',
+    'hidden',
+  ])]
 class EntityFormDisplay extends EntityDisplayBase implements EntityFormDisplayInterface {
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php b/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
index 855e0a1d372c70572a82b004299fe3f945a8e093..24ed8bf55e50affc343aefeb1242cec940df81aa 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityFormMode.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\Entity\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityDisplayModeBase;
 use Drupal\Core\Entity\EntityFormModeInterface;
 
@@ -21,27 +23,28 @@
  *
  * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getAllFormModes()
  * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getFormModes()
- *
- * @ConfigEntityType(
- *   id = "entity_form_mode",
- *   label = @Translation("Form mode"),
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "description" = "description",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "description",
- *     "targetEntityType",
- *     "cache",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "targetEntityType"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'entity_form_mode',
+  label: new TranslatableMarkup('Form mode'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'description' => 'description',
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'targetEntityType',
+    ],
+  ],
+  config_export: [
+    'id',
+    'label',
+    'description',
+    'targetEntityType',
+    'cache',
+  ])]
 class EntityFormMode extends EntityDisplayModeBase implements EntityFormModeInterface {
 
 }
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
index 19cb4219b89a2ebc741fa2aafa0672baa05ac3ee..e2e01b3ec708b7d2ffcd64e876d90bd6c7ad0037 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewDisplay.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\Core\Entity\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\Entity\Access\EntityViewDisplayAccessControlHandler;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
 use Drupal\Core\Entity\EntityDisplayPluginCollection;
@@ -16,30 +19,33 @@
  *
  * Contains display options for all components of a rendered entity in a given
  * view mode.
- *
- * @ConfigEntityType(
- *   id = "entity_view_display",
- *   label = @Translation("Entity view display"),
- *   entity_keys = {
- *     "id" = "id",
- *     "status" = "status"
- *   },
- *   handlers = {
- *     "access" = "\Drupal\Core\Entity\Entity\Access\EntityViewDisplayAccessControlHandler",
- *   },
- *   config_export = {
- *     "id",
- *     "targetEntityType",
- *     "bundle",
- *     "mode",
- *     "content",
- *     "hidden",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "targetEntityType", "bundle", "mode"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'entity_view_display',
+  label: new TranslatableMarkup('Entity view display'),
+  entity_keys: [
+    'id' => 'id',
+    'status' => 'status',
+  ],
+  handlers: [
+    'access' => EntityViewDisplayAccessControlHandler::class,
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'targetEntityType',
+      'bundle',
+      'mode',
+    ],
+  ],
+  config_export: [
+    'id',
+    'targetEntityType',
+    'bundle',
+    'mode',
+    'content',
+    'hidden',
+  ])]
 class EntityViewDisplay extends EntityDisplayBase implements EntityViewDisplayInterface {
 
   /**
diff --git a/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php b/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
index 1d54022454dab98368b1e26bad2c7adb66aa6292..b9aba078a741fdc15d50ecbba20b889eb7c95f73 100644
--- a/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
+++ b/core/lib/Drupal/Core/Entity/Entity/EntityViewMode.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\Core\Entity\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityDisplayModeBase;
 use Drupal\Core\Entity\EntityViewModeInterface;
 
@@ -23,27 +25,28 @@
  * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getAllViewModes()
  * @see \Drupal\Core\Entity\EntityDisplayRepositoryInterface::getViewModes()
  * @see hook_entity_view_mode_info_alter()
- *
- * @ConfigEntityType(
- *   id = "entity_view_mode",
- *   label = @Translation("View mode"),
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "description" = "description",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "description",
- *     "targetEntityType",
- *     "cache",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "targetEntityType"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'entity_view_mode',
+  label: new TranslatableMarkup('View mode'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'description' => 'description',
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'targetEntityType',
+    ],
+  ],
+  config_export: [
+    'id',
+    'label',
+    'description',
+    'targetEntityType',
+    'cache',
+  ])]
 class EntityViewMode extends EntityDisplayModeBase implements EntityViewModeInterface {
 
 }
diff --git a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
index f62b420d3c4633e10b0d2ce21af613ad7096fb39..a06a72f001541fe6e7bc2980a0992212c3841b0f 100644
--- a/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
+++ b/core/lib/Drupal/Core/Entity/EntityStorageInterface.php
@@ -8,8 +8,9 @@
  * For common default implementations, see
  * \Drupal\Core\Entity\Sql\SqlContentEntityStorage for content entities and
  * \Drupal\Core\Config\Entity\ConfigEntityStorage for config entities. Those
- * implementations are used by default when the @ContentEntityType or
- * @ConfigEntityType annotations are used.
+ * implementations are used by default when the
+ * \Drupal\Core\Entity\Attribute\ContentEntityType or
+ * \Drupal\Core\Entity\Attribute\ConfigEntityType attributes are used.
  *
  * @ingroup entity_api
  */
diff --git a/core/lib/Drupal/Core/Entity/EntityTypeManager.php b/core/lib/Drupal/Core/Entity/EntityTypeManager.php
index eb1486de473528e7f8e582395e9e6325dbd183d5..1894b766334e6d64c7443777c194d69bc7e177d1 100644
--- a/core/lib/Drupal/Core/Entity/EntityTypeManager.php
+++ b/core/lib/Drupal/Core/Entity/EntityTypeManager.php
@@ -9,7 +9,8 @@
 use Drupal\Core\Entity\Exception\InvalidLinkTemplateException;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Entity\Attribute\EntityType;
+use Drupal\Core\Plugin\Discovery\AttributeDiscoveryWithAnnotations;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -87,7 +88,7 @@ public function __construct(\Traversable $namespaces, ModuleHandlerInterface $mo
     $this->setCacheBackend($cache, 'entity_type', ['entity_types']);
     $this->alterInfo('entity_type');
 
-    $this->discovery = new AnnotatedClassDiscovery('Entity', $namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
+    $this->discovery = new AttributeDiscoveryWithAnnotations($this->subdir, $this->namespaces, EntityType::class, 'Drupal\Core\Entity\Annotation\EntityType');
     $this->stringTranslation = $string_translation;
     $this->classResolver = $class_resolver;
     $this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository;
diff --git a/core/lib/Drupal/Core/Entity/entity.api.php b/core/lib/Drupal/Core/Entity/entity.api.php
index 09853d9adcac76f69a32f5c5c93610e090106836..bf932e0155ee8e19a69c24e1a27ad9691e9355d6 100644
--- a/core/lib/Drupal/Core/Entity/entity.api.php
+++ b/core/lib/Drupal/Core/Entity/entity.api.php
@@ -367,8 +367,9 @@
  *   for more information.
  * - Define a class for your entity, implementing your interface and extending
  *   either \Drupal\Core\Config\Entity\ConfigEntityBase or
- *   \Drupal\Core\Entity\ContentEntityBase, with annotation for
- *   \@ConfigEntityType or \@ContentEntityType in its documentation block.
+ *   \Drupal\Core\Entity\ContentEntityBase, with a
+ *   \Drupal\Core\Entity\Attribute\ConfigEntityType or
+ *   \Drupal\Core\Entity\Attribute\ContentEntityType attribute set on the class.
  *   If you are defining a content entity type, it is recommended to extend the
  *   \Drupal\Core\Entity\EditorialContentEntityBase base class in order to get
  *   out-of-the-box support for Entity API's revisioning and publishing
diff --git a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
index 1e3cdf81f111eaa9b35c00d5f4293095fd9d9c96..52aed42fcf6ff476e2590aac57fb2e24188c8d86 100644
--- a/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
+++ b/core/lib/Drupal/Core/Field/Entity/BaseFieldOverride.php
@@ -2,6 +2,10 @@
 
 namespace Drupal\Core\Field\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Field\BaseFieldOverrideAccessControlHandler;
+use Drupal\Core\Field\BaseFieldOverrideStorage;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\FieldConfigBase;
@@ -11,38 +15,43 @@
  * Defines the base field override entity.
  *
  * Allows base fields to be overridden on the bundle level.
- *
- * @ConfigEntityType(
- *   id = "base_field_override",
- *   label = @Translation("Base field override"),
- *   handlers = {
- *     "storage" = "Drupal\Core\Field\BaseFieldOverrideStorage",
- *     "access" = "Drupal\Core\Field\BaseFieldOverrideAccessControlHandler",
- *   },
- *   config_prefix = "base_field_override",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "field_name",
- *     "entity_type",
- *     "bundle",
- *     "label",
- *     "description",
- *     "required",
- *     "translatable",
- *     "default_value",
- *     "default_value_callback",
- *     "settings",
- *     "field_type",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "entity_type", "bundle", "field_name", "field_type"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'base_field_override',
+  label: new TranslatableMarkup('Base field override'),
+  config_prefix: 'base_field_override',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'storage' => BaseFieldOverrideStorage::class,
+    'access' => BaseFieldOverrideAccessControlHandler::class,
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'entity_type',
+      'bundle',
+      'field_name',
+      'field_type',
+    ],
+  ],
+  config_export: [
+    'id',
+    'field_name',
+    'entity_type',
+    'bundle',
+    'label',
+    'description',
+    'required',
+    'translatable',
+    'default_value',
+    'default_value_callback',
+    'settings',
+    'field_type',
+  ],
+)]
 class BaseFieldOverride extends FieldConfigBase {
 
   /**
diff --git a/core/modules/block/src/Entity/Block.php b/core/modules/block/src/Entity/Block.php
index 3bc7da26afcf251d38d13adbe5c14b24a35e1c20..5e9c5f0709de9d578751c618858923ff765805d3 100644
--- a/core/modules/block/src/Entity/Block.php
+++ b/core/modules/block/src/Entity/Block.php
@@ -2,6 +2,12 @@
 
 namespace Drupal\block\Entity;
 
+use Drupal\block\BlockAccessControlHandler;
+use Drupal\block\BlockForm;
+use Drupal\block\BlockListBuilder;
+use Drupal\block\BlockViewBuilder;
+use Drupal\block\Form\BlockDeleteForm;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Condition\ConditionPluginCollection;
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
@@ -16,52 +22,51 @@
 
 /**
  * Defines a Block configuration entity class.
- *
- * @ConfigEntityType(
- *   id = "block",
- *   label = @Translation("Block"),
- *   label_collection = @Translation("Blocks"),
- *   label_singular = @Translation("block"),
- *   label_plural = @Translation("blocks"),
- *   label_count = @PluralTranslation(
- *     singular = "@count block",
- *     plural = "@count blocks",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\block\BlockAccessControlHandler",
- *     "view_builder" = "Drupal\block\BlockViewBuilder",
- *     "list_builder" = "Drupal\block\BlockListBuilder",
- *     "form" = {
- *       "default" = "Drupal\block\BlockForm",
- *       "delete" = "Drupal\block\Form\BlockDeleteForm"
- *     }
- *   },
- *   admin_permission = "administer blocks",
- *   entity_keys = {
- *     "id" = "id",
- *     "status" = "status"
- *   },
- *   links = {
- *     "delete-form" = "/admin/structure/block/manage/{block}/delete",
- *     "edit-form" = "/admin/structure/block/manage/{block}",
- *     "enable" = "/admin/structure/block/manage/{block}/enable",
- *     "disable" = "/admin/structure/block/manage/{block}/disable",
- *   },
- *   config_export = {
- *     "id",
- *     "theme",
- *     "region",
- *     "weight",
- *     "provider",
- *     "plugin",
- *     "settings",
- *     "visibility",
- *   },
- *   lookup_keys = {
- *     "theme"
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'block',
+  label: new TranslatableMarkup('Block'),
+  label_collection: new TranslatableMarkup('Blocks'),
+  label_singular: new TranslatableMarkup('block'),
+  label_plural: new TranslatableMarkup('blocks'),
+  entity_keys: [
+    'id' => 'id',
+    'status' => 'status',
+  ],
+  handlers: [
+    'access' => BlockAccessControlHandler::class,
+    'view_builder' => BlockViewBuilder::class,
+    'list_builder' => BlockListBuilder::class,
+    'form' => [
+      'default' => BlockForm::class,
+      'delete' => BlockDeleteForm::class,
+    ],
+  ],
+  links: [
+    'delete-form' => '/admin/structure/block/manage/{block}/delete',
+    'edit-form' => '/admin/structure/block/manage/{block}',
+    'enable' => '/admin/structure/block/manage/{block}/enable',
+    'disable' => '/admin/structure/block/manage/{block}/disable',
+  ],
+  admin_permission: 'administer blocks',
+  label_count: [
+    'singular' => '@count block',
+    'plural' => '@count blocks',
+  ],
+  lookup_keys: [
+    'theme',
+  ],
+  config_export: [
+    'id',
+    'theme',
+    'region',
+    'weight',
+    'provider',
+    'plugin',
+    'settings',
+    'visibility',
+  ],
+)]
 class Block extends ConfigEntityBase implements BlockInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/block_content/src/Entity/BlockContent.php b/core/modules/block_content/src/Entity/BlockContent.php
index 81e6bfcdaeaa29bcb24d4bb15a4063f861dab9b6..b81cdff4c4df8885e3ac66aff89c60fe3c826519 100644
--- a/core/modules/block_content/src/Entity/BlockContent.php
+++ b/core/modules/block_content/src/Entity/BlockContent.php
@@ -2,6 +2,20 @@
 
 namespace Drupal\block_content\Entity;
 
+use Drupal\block_content\BlockContentAccessControlHandler;
+use Drupal\block_content\BlockContentForm;
+use Drupal\block_content\BlockContentListBuilder;
+use Drupal\block_content\BlockContentStorageSchema;
+use Drupal\block_content\BlockContentTranslationHandler;
+use Drupal\block_content\BlockContentViewBuilder;
+use Drupal\block_content\BlockContentViewsData;
+use Drupal\block_content\Form\BlockContentDeleteForm;
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\block_content\Access\RefinableDependentAccessTrait;
 use Drupal\Core\Entity\EditorialContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
@@ -12,79 +26,76 @@
 /**
  * Defines the content block entity class.
  *
- * @ContentEntityType(
- *   id = "block_content",
- *   label = @Translation("Content block"),
- *   label_collection = @Translation("Content blocks"),
- *   label_singular = @Translation("content block"),
- *   label_plural = @Translation("content blocks"),
- *   label_count = @PluralTranslation(
- *     singular = "@count content block",
- *     plural = "@count content blocks",
- *   ),
- *   bundle_label = @Translation("Block type"),
- *   handlers = {
- *     "storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
- *     "storage_schema" = "Drupal\block_content\BlockContentStorageSchema",
- *     "access" = "Drupal\block_content\BlockContentAccessControlHandler",
- *     "list_builder" = "Drupal\block_content\BlockContentListBuilder",
- *     "view_builder" = "Drupal\block_content\BlockContentViewBuilder",
- *     "views_data" = "Drupal\block_content\BlockContentViewsData",
- *     "form" = {
- *       "add" = "Drupal\block_content\BlockContentForm",
- *       "edit" = "Drupal\block_content\BlockContentForm",
- *       "delete" = "Drupal\block_content\Form\BlockContentDeleteForm",
- *       "default" = "Drupal\block_content\BlockContentForm",
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "route_provider" = {
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     },
- *     "translation" = "Drupal\block_content\BlockContentTranslationHandler"
- *   },
- *   admin_permission = "administer block content",
- *   collection_permission = "access block library",
- *   base_table = "block_content",
- *   revision_table = "block_content_revision",
- *   data_table = "block_content_field_data",
- *   revision_data_table = "block_content_field_revision",
- *   show_revision_ui = TRUE,
- *   links = {
- *     "canonical" = "/admin/content/block/{block_content}",
- *     "delete-form" = "/admin/content/block/{block_content}/delete",
- *     "edit-form" = "/admin/content/block/{block_content}",
- *     "collection" = "/admin/content/block",
- *     "create" = "/block",
- *     "revision-delete-form" = "/admin/content/block/{block_content}/revision/{block_content_revision}/delete",
- *     "revision-revert-form" = "/admin/content/block/{block_content}/revision/{block_content_revision}/revert",
- *     "version-history" = "/admin/content/block/{block_content}/revisions",
- *   },
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "revision_id",
- *     "bundle" = "type",
- *     "label" = "info",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "published" = "status",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log"
- *   },
- *   bundle_entity_type = "block_content_type",
- *   field_ui_base_route = "entity.block_content_type.edit_form",
- *   render_cache = FALSE,
- * )
- *
  * Note that render caching of block_content entities is disabled because they
  * are always rendered as blocks, and blocks already have their own render
  * caching.
  * See https://www.drupal.org/node/2284917#comment-9132521 for more information.
  */
+#[ContentEntityType(
+  id: 'block_content',
+  label: new TranslatableMarkup('Content block'),
+  label_collection: new TranslatableMarkup('Content blocks'),
+  label_singular: new TranslatableMarkup('content block'),
+  label_plural: new TranslatableMarkup('content blocks'),
+  render_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'revision_id',
+    'bundle' => 'type',
+    'label' => 'info',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'published' => 'status',
+  ],
+  handlers: [
+    'storage' => SqlContentEntityStorage::class,
+    'storage_schema' => BlockContentStorageSchema::class,
+    'access' => BlockContentAccessControlHandler::class,
+    'list_builder' => BlockContentListBuilder::class,
+    'view_builder' => BlockContentViewBuilder::class,
+    'views_data' => BlockContentViewsData::class,
+    'form' => [
+      'add' => BlockContentForm::class,
+      'edit' => BlockContentForm::class,
+      'delete' => BlockContentDeleteForm::class,
+      'default' => BlockContentForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'route_provider' => ['revision' => RevisionHtmlRouteProvider::class],
+    'translation' => BlockContentTranslationHandler::class,
+  ],
+  links: [
+    'canonical' => '/admin/content/block/{block_content}',
+    'delete-form' => '/admin/content/block/{block_content}/delete',
+    'edit-form' => '/admin/content/block/{block_content}',
+    'collection' => '/admin/content/block',
+    'create' => '/block',
+    'revision-delete-form' => '/admin/content/block/{block_content}/revision/{block_content_revision}/delete',
+    'revision-revert-form' => '/admin/content/block/{block_content}/revision/{block_content_revision}/revert',
+    'version-history' => '/admin/content/block/{block_content}/revisions',
+  ],
+  admin_permission: 'administer block content',
+  collection_permission: 'access block library',
+  bundle_entity_type: 'block_content_type',
+  bundle_label: new TranslatableMarkup('Block type'),
+  base_table: 'block_content',
+  data_table: 'block_content_field_data',
+  revision_table: 'block_content_revision',
+  revision_data_table: 'block_content_field_revision',
+  translatable: TRUE,
+  show_revision_ui: TRUE,
+  label_count: [
+    'singular' => '@count content block',
+    'plural' => '@count content blocks',
+  ],
+  field_ui_base_route: 'entity.block_content_type.edit_form',
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log',
+  ],
+)]
 class BlockContent extends EditorialContentEntityBase implements BlockContentInterface {
 
   use RefinableDependentAccessTrait;
diff --git a/core/modules/block_content/src/Entity/BlockContentType.php b/core/modules/block_content/src/Entity/BlockContentType.php
index c2f22e7fbb5454dbb5299cd0fd3f1dff161ad63a..ecbc6c3866d257074d048aa55f4308c99c33f6b6 100644
--- a/core/modules/block_content/src/Entity/BlockContentType.php
+++ b/core/modules/block_content/src/Entity/BlockContentType.php
@@ -2,57 +2,64 @@
 
 namespace Drupal\block_content\Entity;
 
+use Drupal\block_content\BlockContentTypeForm;
+use Drupal\block_content\BlockContentTypeListBuilder;
+use Drupal\block_content\BlockTypeAccessControlHandler;
+use Drupal\block_content\Form\BlockContentTypeDeleteForm;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\block_content\BlockContentTypeInterface;
+use Drupal\user\Entity\EntityPermissionsRouteProvider;
 
 /**
  * Defines the block type entity.
- *
- * @ConfigEntityType(
- *   id = "block_content_type",
- *   label = @Translation("Block type"),
- *   label_collection = @Translation("Block types"),
- *   label_singular = @Translation("block type"),
- *   label_plural = @Translation("block types"),
- *   label_count = @PluralTranslation(
- *     singular = "@count block type",
- *     plural = "@count block types",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\block_content\BlockTypeAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\block_content\BlockContentTypeForm",
- *       "add" = "Drupal\block_content\BlockContentTypeForm",
- *       "edit" = "Drupal\block_content\BlockContentTypeForm",
- *       "delete" = "Drupal\block_content\Form\BlockContentTypeDeleteForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
- *       "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
- *     },
- *     "list_builder" = "Drupal\block_content\BlockContentTypeListBuilder"
- *   },
- *   admin_permission = "administer block types",
- *   config_prefix = "type",
- *   bundle_of = "block_content",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   links = {
- *     "delete-form" = "/admin/structure/block-content/manage/{block_content_type}/delete",
- *     "edit-form" = "/admin/structure/block-content/manage/{block_content_type}",
- *     "entity-permissions-form" = "/admin/structure/block-content/manage/{block_content_type}/permissions",
- *     "collection" = "/admin/structure/block-content",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "revision",
- *     "description",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'block_content_type',
+  label: new TranslatableMarkup('Block type'),
+  label_collection: new TranslatableMarkup('Block types'),
+  label_singular: new TranslatableMarkup('block type'),
+  label_plural: new TranslatableMarkup('block types'),
+  config_prefix: 'type',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'access' => BlockTypeAccessControlHandler::class,
+    'form' => [
+      'default' => BlockContentTypeForm::class,
+      'add' => BlockContentTypeForm::class,
+      'edit' => BlockContentTypeForm::class,
+      'delete' => BlockContentTypeDeleteForm::class,
+    ],
+    'route_provider' => [
+      'html' => AdminHtmlRouteProvider::class,
+      'permissions' => EntityPermissionsRouteProvider::class,
+    ],
+    'list_builder' => BlockContentTypeListBuilder::class,
+  ],
+  links: [
+    'delete-form' => '/admin/structure/block-content/manage/{block_content_type}/delete',
+    'edit-form' => '/admin/structure/block-content/manage/{block_content_type}',
+    'entity-permissions-form' => '/admin/structure/block-content/manage/{block_content_type}/permissions',
+    'collection' => '/admin/structure/block-content',
+  ],
+  admin_permission: 'administer block types',
+  bundle_of: 'block_content',
+  label_count: [
+    'singular' => '@count block type',
+    'plural' => '@count block types',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'revision',
+    'description',
+  ],
+)]
 class BlockContentType extends ConfigEntityBundleBase implements BlockContentTypeInterface {
 
   /**
diff --git a/core/modules/comment/src/Entity/Comment.php b/core/modules/comment/src/Entity/Comment.php
index 43123b7a17ff697b5a34a5d3fc85938aa4f586f3..5d734aeecd771f26bef408c93271f2f8231004e3 100644
--- a/core/modules/comment/src/Entity/Comment.php
+++ b/core/modules/comment/src/Entity/Comment.php
@@ -2,6 +2,17 @@
 
 namespace Drupal\comment\Entity;
 
+use Drupal\comment\CommentAccessControlHandler;
+use Drupal\comment\CommentForm;
+use Drupal\comment\CommentStorage;
+use Drupal\comment\CommentStorageSchema;
+use Drupal\comment\CommentTranslationHandler;
+use Drupal\comment\CommentViewBuilder;
+use Drupal\comment\CommentViewsData;
+use Drupal\comment\Form\DeleteForm;
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Component\Utility\Number;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\ContentEntityBase;
@@ -17,57 +28,56 @@
 
 /**
  * Defines the comment entity class.
- *
- * @ContentEntityType(
- *   id = "comment",
- *   label = @Translation("Comment"),
- *   label_singular = @Translation("comment"),
- *   label_plural = @Translation("comments"),
- *   label_count = @PluralTranslation(
- *     singular = "@count comment",
- *     plural = "@count comments",
- *   ),
- *   bundle_label = @Translation("Comment type"),
- *   handlers = {
- *     "storage" = "Drupal\comment\CommentStorage",
- *     "storage_schema" = "Drupal\comment\CommentStorageSchema",
- *     "access" = "Drupal\comment\CommentAccessControlHandler",
- *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
- *     "view_builder" = "Drupal\comment\CommentViewBuilder",
- *     "views_data" = "Drupal\comment\CommentViewsData",
- *     "form" = {
- *       "default" = "Drupal\comment\CommentForm",
- *       "delete" = "Drupal\comment\Form\DeleteForm"
- *     },
- *     "translation" = "Drupal\comment\CommentTranslationHandler"
- *   },
- *   base_table = "comment",
- *   data_table = "comment_field_data",
- *   uri_callback = "comment_uri",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "cid",
- *     "bundle" = "comment_type",
- *     "label" = "subject",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "published" = "status",
- *     "owner" = "uid",
- *   },
- *   links = {
- *     "canonical" = "/comment/{comment}",
- *     "delete-form" = "/comment/{comment}/delete",
- *     "delete-multiple-form" = "/admin/content/comment/delete",
- *     "edit-form" = "/comment/{comment}/edit",
- *     "create" = "/comment",
- *   },
- *   bundle_entity_type = "comment_type",
- *   field_ui_base_route  = "entity.comment_type.edit_form",
- *   constraints = {
- *     "CommentName" = {}
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'comment',
+  label: new TranslatableMarkup('Comment'),
+  label_singular: new TranslatableMarkup('comment'),
+  label_plural: new TranslatableMarkup('comments'),
+  entity_keys: [
+    'id' => 'cid',
+    'bundle' => 'comment_type',
+    'label' => 'subject',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'published' => 'status',
+    'owner' => 'uid',
+  ],
+  handlers: [
+    'storage' => CommentStorage::class,
+    'storage_schema' => CommentStorageSchema::class,
+    'access' => CommentAccessControlHandler::class,
+    'list_builder' => EntityListBuilder::class,
+    'view_builder' => CommentViewBuilder::class,
+    'views_data' => CommentViewsData::class,
+    'form' => [
+      'default' => CommentForm::class,
+      'delete' => DeleteForm::class,
+    ],
+    'translation' => CommentTranslationHandler::class,
+  ],
+  links: [
+    'canonical' => '/comment/{comment}',
+    'delete-form' => '/comment/{comment}/delete',
+    'delete-multiple-form' => '/admin/content/comment/delete',
+    'edit-form' => '/comment/{comment}/edit',
+    'create' => '/comment',
+  ],
+  bundle_entity_type: 'comment_type',
+  bundle_label: new TranslatableMarkup('Comment type'),
+  base_table: 'comment',
+  data_table: 'comment_field_data',
+  translatable: TRUE,
+  label_count: [
+    'singular' => '@count comment',
+    'plural' => '@count comments',
+  ],
+  uri_callback: 'comment_uri',
+  field_ui_base_route: 'entity.comment_type.edit_form',
+  constraints: [
+    'CommentName' => [],
+  ],
+)]
 class Comment extends ContentEntityBase implements CommentInterface {
 
   use EntityChangedTrait;
diff --git a/core/modules/comment/src/Entity/CommentType.php b/core/modules/comment/src/Entity/CommentType.php
index 5cee3668898d2c2e60fc50954dba43d5fd87af7e..6dcf75d9e8a750e3be194be1f17bce5b28e30b67 100644
--- a/core/modules/comment/src/Entity/CommentType.php
+++ b/core/modules/comment/src/Entity/CommentType.php
@@ -2,55 +2,60 @@
 
 namespace Drupal\comment\Entity;
 
+use Drupal\comment\CommentTypeForm;
+use Drupal\comment\CommentTypeListBuilder;
+use Drupal\comment\Form\CommentTypeDeleteForm;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\comment\CommentTypeInterface;
+use Drupal\user\Entity\EntityPermissionsRouteProvider;
 
 /**
  * Defines the comment type entity.
- *
- * @ConfigEntityType(
- *   id = "comment_type",
- *   label = @Translation("Comment type"),
- *   label_singular = @Translation("comment type"),
- *   label_plural = @Translation("comment types"),
- *   label_count = @PluralTranslation(
- *     singular = "@count comment type",
- *     plural = "@count comment types",
- *   ),
- *   handlers = {
- *     "form" = {
- *       "default" = "Drupal\comment\CommentTypeForm",
- *       "add" = "Drupal\comment\CommentTypeForm",
- *       "edit" = "Drupal\comment\CommentTypeForm",
- *       "delete" = "Drupal\comment\Form\CommentTypeDeleteForm"
- *     },
- *     "route_provider" = {
- *       "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
- *     },
- *     "list_builder" = "Drupal\comment\CommentTypeListBuilder"
- *   },
- *   admin_permission = "administer comment types",
- *   config_prefix = "type",
- *   bundle_of = "comment",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   links = {
- *     "delete-form" = "/admin/structure/comment/manage/{comment_type}/delete",
- *     "edit-form" = "/admin/structure/comment/manage/{comment_type}",
- *     "add-form" = "/admin/structure/comment/types/add",
- *     "entity-permissions-form" = "/admin/structure/comment/manage/{comment_type}/permissions",
- *     "collection" = "/admin/structure/comment",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "target_entity_type_id",
- *     "description",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'comment_type',
+  label: new TranslatableMarkup('Comment type'),
+  label_singular: new TranslatableMarkup('comment type'),
+  label_plural: new TranslatableMarkup('comment types'),
+  config_prefix: 'type',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'form' => [
+      'default' => CommentTypeForm::class,
+      'add' => CommentTypeForm::class,
+      'edit' => CommentTypeForm::class,
+      'delete' => CommentTypeDeleteForm::class,
+    ],
+    'route_provider' => [
+      'permissions' => EntityPermissionsRouteProvider::class,
+    ],
+    'list_builder' => CommentTypeListBuilder::class,
+  ],
+  links: [
+    'delete-form' => '/admin/structure/comment/manage/{comment_type}/delete',
+    'edit-form' => '/admin/structure/comment/manage/{comment_type}',
+    'add-form' => '/admin/structure/comment/types/add',
+    'entity-permissions-form' => '/admin/structure/comment/manage/{comment_type}/permissions',
+    'collection' => '/admin/structure/comment',
+  ],
+  admin_permission: 'administer comment types',
+  bundle_of: 'comment',
+  label_count: [
+    'singular' => '@count comment type',
+    'plural' => '@count comment types',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'target_entity_type_id',
+    'description',
+  ],
+)]
 class CommentType extends ConfigEntityBundleBase implements CommentTypeInterface {
 
   /**
diff --git a/core/modules/comment/tests/modules/comment_base_field_test/src/Entity/CommentTestBaseField.php b/core/modules/comment/tests/modules/comment_base_field_test/src/Entity/CommentTestBaseField.php
index 30fe7b00438a5b81a46ef0f98a27c578c982c0a3..de39ded5f7f5c2d144c9d94b459fbd89fbb389a0 100644
--- a/core/modules/comment/tests/modules/comment_base_field_test/src/Entity/CommentTestBaseField.php
+++ b/core/modules/comment/tests/modules/comment_base_field_test/src/Entity/CommentTestBaseField.php
@@ -4,6 +4,8 @@
 
 namespace Drupal\comment_base_field_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
@@ -11,18 +13,17 @@
 
 /**
  * Defines a test entity class for comment as a base field.
- *
- * @ContentEntityType(
- *   id = "comment_test_base_field",
- *   label = @Translation("Test comment - base field"),
- *   base_table = "comment_test_base_field",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type"
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'comment_test_base_field',
+  label: new TranslatableMarkup('Test comment - base field'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+  ],
+  base_table: 'comment_test_base_field'
+)]
 class CommentTestBaseField extends EntityTest {
 
   public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
diff --git a/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php b/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php
index 44afcb4ea3aa34f9bbbe7682b6974f1bb4048be2..0e36c3d58f93e531bbac867439354584be3597ed 100644
--- a/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php
+++ b/core/modules/config/tests/config_test/src/Entity/ConfigQueryTest.php
@@ -4,34 +4,40 @@
 
 namespace Drupal\config_test\Entity;
 
+use Drupal\config_test\ConfigTestForm;
+use Drupal\config_test\ConfigTestStorage;
+use Drupal\Core\Config\Entity\ConfigEntityListBuilder;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Defines the ConfigQueryTest configuration entity used by the query test.
  *
- * @ConfigEntityType(
- *   id = "config_query_test",
- *   label = @Translation("Test configuration for query"),
- *   handlers = {
- *     "storage" = "Drupal\config_test\ConfigTestStorage",
- *     "list_builder" = "Drupal\Core\Config\Entity\ConfigEntityListBuilder",
- *     "form" = {
- *       "default" = "Drupal\config_test\ConfigTestForm"
- *     }
- *   },
- *   config_prefix = "query",
- *   config_export = {
- *     "id",
- *     "label",
- *     "array",
- *     "number",
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   }
- * )
  *
  * @see \Drupal\system\Tests\Entity\ConfigEntityQueryTest
  */
+#[ConfigEntityType(
+  id: 'config_query_test',
+  label: new TranslatableMarkup('Test configuration for query'),
+  config_prefix: 'query',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'storage' => ConfigTestStorage::class,
+    'list_builder' => ConfigEntityListBuilder::class,
+    'form' => [
+      'default' => ConfigTestForm::class,
+    ],
+  ],
+  config_export: [
+    'id',
+    'label',
+    'array',
+    'number',
+  ],
+)]
 class ConfigQueryTest extends ConfigTest {
 
   /**
diff --git a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
index 80022dc60e3fb77236227bb39c0897db88ab8c8a..412aff95ae1d038b43cd27ce0470c5bf192c2e65 100644
--- a/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
+++ b/core/modules/config/tests/config_test/src/Entity/ConfigTest.php
@@ -4,53 +4,57 @@
 
 namespace Drupal\config_test\Entity;
 
+use Drupal\config_test\ConfigTestAccessControlHandler;
+use Drupal\config_test\ConfigTestForm;
+use Drupal\config_test\ConfigTestInterface;
+use Drupal\config_test\ConfigTestListBuilder;
+use Drupal\config_test\ConfigTestStorage;
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
-use Drupal\config_test\ConfigTestInterface;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityDeleteForm;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 
 /**
  * Defines the ConfigTest configuration entity.
- *
- * @ConfigEntityType(
- *   id = "config_test",
- *   label = @Translation("Test configuration"),
- *   handlers = {
- *     "storage" = "Drupal\config_test\ConfigTestStorage",
- *     "list_builder" = "Drupal\config_test\ConfigTestListBuilder",
- *     "form" = {
- *       "default" = "Drupal\config_test\ConfigTestForm",
- *       "delete" = "Drupal\Core\Entity\EntityDeleteForm"
- *     },
- *     "access" = "Drupal\config_test\ConfigTestAccessControlHandler"
- *   },
- *   config_prefix = "dynamic",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "status" = "status"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "weight",
- *     "style",
- *     "size",
- *     "size_value",
- *     "protected_property",
- *     "array_property",
- *   },
- *   links = {
- *     "edit-form" = "/admin/structure/config_test/manage/{config_test}",
- *     "delete-form" = "/admin/structure/config_test/manage/{config_test}/delete",
- *     "enable" = "/admin/structure/config_test/manage/{config_test}/enable",
- *     "disable" = "/admin/structure/config_test/manage/{config_test}/disable",
- *     "collection" = "/admin/structure/config_test",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'config_test',
+  label: new TranslatableMarkup('Test configuration'),
+  config_prefix: 'dynamic',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'status' => 'status',
+  ],
+  handlers: [
+    'storage' => ConfigTestStorage::class,
+    'list_builder' => ConfigTestListBuilder::class,
+    'form' => [
+      'default' => ConfigTestForm::class,
+      'delete' => EntityDeleteForm::class,
+    ],
+    'access' => ConfigTestAccessControlHandler::class,
+  ],
+  links: [
+    'edit-form' => '/admin/structure/config_test/manage/{config_test}',
+    'delete-form' => '/admin/structure/config_test/manage/{config_test}/delete',
+    'enable' => '/admin/structure/config_test/manage/{config_test}/enable',
+    'disable' => '/admin/structure/config_test/manage/{config_test}/disable',
+    'collection' => '/admin/structure/config_test',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'weight',
+    'style',
+    'size',
+    'size_value',
+    'protected_property',
+    'array_property',
+  ])]
 class ConfigTest extends ConfigEntityBase implements ConfigTestInterface {
 
   /**
diff --git a/core/modules/contact/src/Entity/ContactForm.php b/core/modules/contact/src/Entity/ContactForm.php
index 641243b66d4fcb60c4d9a7f936ba6ee24a045c60..d24ceb2c50319f61da44bac68464c91536b0603d 100644
--- a/core/modules/contact/src/Entity/ContactForm.php
+++ b/core/modules/contact/src/Entity/ContactForm.php
@@ -2,62 +2,65 @@
 
 namespace Drupal\contact\Entity;
 
+use Drupal\contact\ContactFormAccessControlHandler;
+use Drupal\contact\ContactFormEditForm;
+use Drupal\contact\ContactFormInterface;
+use Drupal\contact\ContactFormListBuilder;
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
-use Drupal\contact\ContactFormInterface;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityDeleteForm;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\user\Entity\EntityPermissionsRouteProvider;
 
 /**
  * Defines the contact form entity.
- *
- * @ConfigEntityType(
- *   id = "contact_form",
- *   label = @Translation("Contact form"),
- *   label_collection = @Translation("Contact forms"),
- *   label_singular = @Translation("contact form"),
- *   label_plural = @Translation("contact forms"),
- *   label_count = @PluralTranslation(
- *     singular = "@count contact form",
- *     plural = "@count contact forms",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\contact\ContactFormAccessControlHandler",
- *     "list_builder" = "Drupal\contact\ContactFormListBuilder",
- *     "form" = {
- *       "add" = "Drupal\contact\ContactFormEditForm",
- *       "edit" = "Drupal\contact\ContactFormEditForm",
- *       "delete" = "Drupal\Core\Entity\EntityDeleteForm"
- *     },
- *     "route_provider" = {
- *       "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
- *     }
- *   },
- *   config_prefix = "form",
- *   admin_permission = "administer contact forms",
- *   bundle_of = "contact_message",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   links = {
- *     "delete-form" = "/admin/structure/contact/manage/{contact_form}/delete",
- *     "edit-form" = "/admin/structure/contact/manage/{contact_form}",
- *     "entity-permissions-form" = "/admin/structure/contact/manage/{contact_form}/permissions",
- *     "collection" = "/admin/structure/contact",
- *     "canonical" = "/contact/{contact_form}",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "recipients",
- *     "reply",
- *     "weight",
- *     "message",
- *     "redirect",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'contact_form',
+  label: new TranslatableMarkup('Contact form'),
+  label_collection: new TranslatableMarkup('Contact forms'),
+  label_singular: new TranslatableMarkup('contact form'),
+  label_plural: new TranslatableMarkup('contact forms'),
+  config_prefix: 'form',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'access' => ContactFormAccessControlHandler::class,
+    'list_builder' => ContactFormListBuilder::class,
+    'form' => [
+      'add' => ContactFormEditForm::class,
+      'edit' => ContactFormEditForm::class,
+      'delete' => EntityDeleteForm::class,
+    ],
+    'route_provider' => ['permissions' => EntityPermissionsRouteProvider::class],
+  ],
+  links: [
+    'delete-form' => '/admin/structure/contact/manage/{contact_form}/delete',
+    'edit-form' => '/admin/structure/contact/manage/{contact_form}',
+    'entity-permissions-form' => '/admin/structure/contact/manage/{contact_form}/permissions',
+    'collection' => '/admin/structure/contact',
+    'canonical' => '/contact/{contact_form}',
+  ],
+  admin_permission: 'administer contact forms',
+  bundle_of: 'contact_message',
+  label_count: [
+    'singular' => '@count contact form',
+    'plural' => '@count contact forms',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'recipients',
+    'reply',
+    'weight',
+    'message',
+    'redirect',
+  ],
+)]
 class ContactForm extends ConfigEntityBundleBase implements ContactFormInterface {
 
   /**
diff --git a/core/modules/contact/src/Entity/Message.php b/core/modules/contact/src/Entity/Message.php
index f41d9f106f058b552a441ab2a1db877e301e3cdd..16eae76660c470c6c7112ae930d956c373a9918c 100644
--- a/core/modules/contact/src/Entity/Message.php
+++ b/core/modules/contact/src/Entity/Message.php
@@ -2,6 +2,12 @@
 
 namespace Drupal\contact\Entity;
 
+use Drupal\contact\ContactMessageAccessControlHandler;
+use Drupal\contact\MessageForm;
+use Drupal\contact\MessageViewBuilder;
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\ContentEntityNullStorage;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\contact\MessageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
@@ -9,36 +15,33 @@
 
 /**
  * Defines the contact message entity.
- *
- * @ContentEntityType(
- *   id = "contact_message",
- *   label = @Translation("Contact message"),
- *   label_collection = @Translation("Contact messages"),
- *   label_singular = @Translation("contact message"),
- *   label_plural = @Translation("contact messages"),
- *   label_count = @PluralTranslation(
- *     singular = "@count contact message",
- *     plural = "@count contact messages",
- *   ),
- *   bundle_label = @Translation("Contact form"),
- *   handlers = {
- *     "access" = "Drupal\contact\ContactMessageAccessControlHandler",
- *     "storage" = "Drupal\Core\Entity\ContentEntityNullStorage",
- *     "view_builder" = "Drupal\contact\MessageViewBuilder",
- *     "form" = {
- *       "default" = "Drupal\contact\MessageForm"
- *     }
- *   },
- *   admin_permission = "administer contact forms",
- *   entity_keys = {
- *     "bundle" = "contact_form",
- *     "uuid" = "uuid",
- *     "langcode" = "langcode"
- *   },
- *   bundle_entity_type = "contact_form",
- *   field_ui_base_route = "entity.contact_form.edit_form",
- * )
  */
+#[ContentEntityType(
+  id: 'contact_message',
+  label: new TranslatableMarkup('Contact message'),
+  label_collection: new TranslatableMarkup('Contact messages'),
+  label_singular: new TranslatableMarkup('contact message'),
+  label_plural: new TranslatableMarkup('contact messages'),
+  entity_keys: [
+    'bundle' => 'contact_form',
+    'uuid' => 'uuid',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => ContactMessageAccessControlHandler::class,
+    'storage' => ContentEntityNullStorage::class,
+    'view_builder' => MessageViewBuilder::class,
+    'form' => ['default' => MessageForm::class],
+  ],
+  admin_permission: 'administer contact forms',
+  bundle_entity_type: 'contact_form',
+  bundle_label: new TranslatableMarkup('Contact form'),
+  label_count: [
+    'singular' => '@count contact message',
+    'plural' => '@count contact messages',
+  ],
+  field_ui_base_route: 'entity.contact_form.edit_form'
+)]
 class Message extends ContentEntityBase implements MessageInterface {
 
   /**
diff --git a/core/modules/content_moderation/src/Entity/ContentModerationState.php b/core/modules/content_moderation/src/Entity/ContentModerationState.php
index 31d7856194a37f70283c0d9910d63919b935cbbf..85ef099318566ce8d4e057aac393a10c88dbfa36 100644
--- a/core/modules/content_moderation/src/Entity/ContentModerationState.php
+++ b/core/modules/content_moderation/src/Entity/ContentModerationState.php
@@ -2,51 +2,56 @@
 
 namespace Drupal\content_moderation\Entity;
 
+use Drupal\content_moderation\ContentModerationStateAccessControlHandler;
+use Drupal\content_moderation\ContentModerationStateStorageSchema;
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\TypedData\TranslatableInterface;
 use Drupal\user\EntityOwnerTrait;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the Content moderation state entity.
  *
- * @ContentEntityType(
- *   id = "content_moderation_state",
- *   label = @Translation("Content moderation state"),
- *   label_singular = @Translation("content moderation state"),
- *   label_plural = @Translation("content moderation states"),
- *   label_count = @PluralTranslation(
- *     singular = "@count content moderation state",
- *     plural = "@count content moderation states"
- *   ),
- *   handlers = {
- *     "storage_schema" = "Drupal\content_moderation\ContentModerationStateStorageSchema",
- *     "views_data" = "\Drupal\views\EntityViewsData",
- *     "access" = "Drupal\content_moderation\ContentModerationStateAccessControlHandler",
- *   },
- *   base_table = "content_moderation_state",
- *   revision_table = "content_moderation_state_revision",
- *   data_table = "content_moderation_state_field_data",
- *   revision_data_table = "content_moderation_state_field_revision",
- *   translatable = TRUE,
- *   internal = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "revision_id",
- *     "uuid" = "uuid",
- *     "uid" = "uid",
- *     "owner" = "uid",
- *     "langcode" = "langcode",
- *   }
- * )
  *
  * @internal
  *   This entity is marked internal because it should not be used directly to
  *   alter the moderation state of an entity. Instead, the computed
  *   moderation_state field should be set on the entity directly.
  */
+#[ContentEntityType(
+  id: 'content_moderation_state',
+  label: new TranslatableMarkup('Content moderation state'),
+  label_singular: new TranslatableMarkup('content moderation state'),
+  label_plural: new TranslatableMarkup('content moderation states'),
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'revision_id',
+    'uuid' => 'uuid',
+    'uid' => 'uid',
+    'owner' => 'uid',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'storage_schema' => ContentModerationStateStorageSchema::class,
+    'views_data' => EntityViewsData::class,
+    'access' => ContentModerationStateAccessControlHandler::class,
+  ],
+  base_table: 'content_moderation_state',
+  data_table: 'content_moderation_state_field_data',
+  revision_table: 'content_moderation_state_revision',
+  revision_data_table: 'content_moderation_state_field_revision',
+  internal: TRUE,
+  translatable: TRUE,
+  label_count: [
+    'singular' => '@count content moderation state',
+    'plural' => '@count content moderation states',
+  ],
+)]
 class ContentModerationState extends ContentEntityBase implements ContentModerationStateInterface {
 
   use EntityOwnerTrait;
diff --git a/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableNoUISkip.php b/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableNoUISkip.php
index 4a884284466f8366e37bd2ecbf0babf823fe5c82..4728be44c3a0bce79dfcf832355160ff627136e1 100644
--- a/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableNoUISkip.php
+++ b/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableNoUISkip.php
@@ -4,38 +4,39 @@
 
 namespace Drupal\content_translation_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\entity_test\Entity\EntityTest;
+use Drupal\entity_test\EntityTestForm;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_translatable_no_skip",
- *   label = @Translation("Test entity - Translatable check UI"),
- *   handlers = {
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *      },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_mul",
- *   data_table = "entity_test_mul_property_data",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   translatable = TRUE,
- *   admin_permission = "administer entity_test content",
- *   links = {
- *     "edit-form" = "/entity_test_translatable_no_skip/{entity_test_translatable_no_skip}/edit",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_translatable_no_skip',
+  label: new TranslatableMarkup('Test entity - Translatable check UI'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'form' => ['default' => EntityTestForm::class],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'edit-form' => '/entity_test_translatable_no_skip/{entity_test_translatable_no_skip}/edit',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_mul',
+  data_table: 'entity_test_mul_property_data',
+  translatable: TRUE,
+)]
 class EntityTestTranslatableNoUISkip extends EntityTest {
 
 }
diff --git a/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableUISkip.php b/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableUISkip.php
index aff265578bb1fd69b338ac38a97134fcce65137c..c95da3b4b82a721faa64676982efc327e3518f46 100644
--- a/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableUISkip.php
+++ b/core/modules/content_translation/tests/modules/content_translation_test/src/Entity/EntityTestTranslatableUISkip.php
@@ -4,27 +4,30 @@
 
 namespace Drupal\content_translation_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\entity_test\Entity\EntityTest;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_translatable_UI_skip",
- *   label = @Translation("Test entity - Translatable skip UI check"),
- *   base_table = "entity_test_mul",
- *   data_table = "entity_test_mul_property_data",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   translatable = TRUE,
- *   content_translation_ui_skip = TRUE,
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_translatable_UI_skip',
+  label: new TranslatableMarkup('Test entity - Translatable skip UI check'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  base_table: 'entity_test_mul',
+  data_table: 'entity_test_mul_property_data',
+  translatable: TRUE,
+  additional: [
+    'content_translation_ui_skip' => TRUE,
+  ],
+)]
 class EntityTestTranslatableUISkip extends EntityTest {
 
 }
diff --git a/core/modules/editor/src/Entity/Editor.php b/core/modules/editor/src/Entity/Editor.php
index 54d32a8dcbf7137d190234d0dc2ad8d448a71a63..2b55b4c884e8f515ecebd4705c8f4a9dac6b9aa8 100644
--- a/core/modules/editor/src/Entity/Editor.php
+++ b/core/modules/editor/src/Entity/Editor.php
@@ -2,9 +2,12 @@
 
 namespace Drupal\editor\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\StreamWrapper\StreamWrapperInterface;
+use Drupal\editor\EditorAccessControlHandler;
 use Drupal\editor\EditorInterface;
 
 /**
@@ -14,36 +17,35 @@
  * saved after selecting an editor plugin (eg: CKEditor). The ID of the
  * Editor entity will be same as the ID of the filter format entity in which
  * the editor plugin was selected.
- *
- * @ConfigEntityType(
- *   id = "editor",
- *   label = @Translation("Text editor"),
- *   label_collection = @Translation("Text editors"),
- *   label_singular = @Translation("text editor"),
- *   label_plural = @Translation("text editors"),
- *   label_count = @PluralTranslation(
- *     singular = "@count text editor",
- *     plural = "@count text editors",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\editor\EditorAccessControlHandler",
- *   },
- *   entity_keys = {
- *     "id" = "format"
- *   },
- *   config_export = {
- *     "format",
- *     "editor",
- *     "settings",
- *     "image_upload",
- *   },
- *   constraints = {
- *     "RequiredConfigDependencies" = {
- *       "filter_format"
- *     }
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'editor',
+  label: new TranslatableMarkup('Text editor'),
+  label_collection: new TranslatableMarkup('Text editors'),
+  label_singular: new TranslatableMarkup('text editor'),
+  label_plural: new TranslatableMarkup('text editors'),
+  entity_keys: [
+    'id' => 'format',
+  ],
+  handlers: [
+    'access' => EditorAccessControlHandler::class,
+  ],
+  label_count: [
+    'singular' => '@count text editor',
+    'plural' => '@count text editors',
+  ],
+  constraints: [
+    'RequiredConfigDependencies' => [
+      'filter_format',
+    ],
+  ],
+  config_export: [
+    'format',
+    'editor',
+    'settings',
+    'image_upload',
+  ],
+)]
 class Editor extends ConfigEntityBase implements EditorInterface {
 
   /**
diff --git a/core/modules/field/src/Entity/FieldConfig.php b/core/modules/field/src/Entity/FieldConfig.php
index 09db516b174a78da8bd1812714b133923f2119fb..40417dea44050c6e77de456ef2f33cf38379f624 100644
--- a/core/modules/field/src/Entity/FieldConfig.php
+++ b/core/modules/field/src/Entity/FieldConfig.php
@@ -2,57 +2,64 @@
 
 namespace Drupal\field\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\FieldableEntityStorageInterface;
 use Drupal\Core\Field\FieldConfigBase;
 use Drupal\Core\Field\FieldException;
+use Drupal\field\FieldConfigAccessControlHandler;
+use Drupal\field\FieldConfigStorage;
 use Drupal\field\FieldStorageConfigInterface;
 use Drupal\field\FieldConfigInterface;
 
 /**
  * Defines the Field entity.
- *
- * @ConfigEntityType(
- *   id = "field_config",
- *   label = @Translation("Field"),
- *   label_collection = @Translation("Fields"),
- *   label_singular = @Translation("field"),
- *   label_plural = @Translation("fields"),
- *   label_count = @PluralTranslation(
- *     singular = "@count field",
- *     plural = "@count fields",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\field\FieldConfigAccessControlHandler",
- *     "storage" = "Drupal\field\FieldConfigStorage"
- *   },
- *   config_prefix = "field",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "field_name",
- *     "entity_type",
- *     "bundle",
- *     "label",
- *     "description",
- *     "required",
- *     "translatable",
- *     "default_value",
- *     "default_value_callback",
- *     "settings",
- *     "field_type",
- *   },
- *   constraints = {
- *     "RequiredConfigDependencies" = {
- *       "field_storage_config"
- *     },
- *     "ImmutableProperties" = {"id", "entity_type", "field_name", "bundle", "field_type"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'field_config',
+  label: new TranslatableMarkup('Field'),
+  label_collection: new TranslatableMarkup('Fields'),
+  label_singular: new TranslatableMarkup('field'),
+  label_plural: new TranslatableMarkup('fields'),
+  config_prefix: 'field',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'access' => FieldConfigAccessControlHandler::class,
+    'storage' => FieldConfigStorage::class,
+  ],
+  label_count: [
+    'singular' => '@count field',
+    'plural' => '@count fields',
+  ],
+  constraints: [
+    'RequiredConfigDependencies' => ['field_storage_config'],
+    'ImmutableProperties' => [
+      'id',
+      'entity_type',
+      'field_name',
+      'bundle',
+      'field_type',
+    ],
+  ],
+  config_export: [
+    'id',
+    'field_name',
+    'entity_type',
+    'bundle',
+    'label',
+    'description',
+    'required',
+    'translatable',
+    'default_value',
+    'default_value_callback',
+    'settings',
+    'field_type',
+  ],
+)]
 class FieldConfig extends FieldConfigBase implements FieldConfigInterface {
 
   /**
diff --git a/core/modules/field/src/Entity/FieldStorageConfig.php b/core/modules/field/src/Entity/FieldStorageConfig.php
index c399cd5392ae5fb316c340e2abff940d2d8658d1..9c3086dd51f95fd3799d868736b72f12ccf55eac 100644
--- a/core/modules/field/src/Entity/FieldStorageConfig.php
+++ b/core/modules/field/src/Entity/FieldStorageConfig.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\field\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\FieldableEntityInterface;
@@ -11,49 +13,55 @@
 use Drupal\Core\Field\FieldException;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\TypedData\OptionsProviderInterface;
+use Drupal\field\FieldStorageConfigAccessControlHandler;
 use Drupal\field\FieldStorageConfigInterface;
+use Drupal\field\FieldStorageConfigStorage;
 
 /**
  * Defines the Field storage configuration entity.
- *
- * @ConfigEntityType(
- *   id = "field_storage_config",
- *   label = @Translation("Field storage"),
- *   label_collection = @Translation("Field storages"),
- *   label_singular = @Translation("field storage"),
- *   label_plural = @Translation("field storages"),
- *   label_count = @PluralTranslation(
- *     singular = "@count field storage",
- *     plural = "@count field storages",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\field\FieldStorageConfigAccessControlHandler",
- *     "storage" = "Drupal\field\FieldStorageConfigStorage"
- *   },
- *   config_prefix = "storage",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "id"
- *   },
- *   config_export = {
- *     "id",
- *     "field_name",
- *     "entity_type",
- *     "type",
- *     "settings",
- *     "module",
- *     "locked",
- *     "cardinality",
- *     "translatable",
- *     "indexes",
- *     "persist_with_no_fields",
- *     "custom_storage",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "entity_type", "field_name", "type"},
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'field_storage_config',
+  label: new TranslatableMarkup('Field storage'),
+  label_collection: new TranslatableMarkup('Field storages'),
+  label_singular: new TranslatableMarkup('field storage'),
+  label_plural: new TranslatableMarkup('field storages'),
+  config_prefix: 'storage',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'id',
+  ],
+  handlers: [
+    'access' => FieldStorageConfigAccessControlHandler::class,
+    'storage' => FieldStorageConfigStorage::class,
+  ],
+  label_count: [
+    'singular' => '@count field storage',
+    'plural' => '@count field storages',
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'entity_type',
+      'field_name',
+      'type',
+    ],
+  ],
+  config_export: [
+    'id',
+    'field_name',
+    'entity_type',
+    'type',
+    'settings',
+    'module',
+    'locked',
+    'cardinality',
+    'translatable',
+    'indexes',
+    'persist_with_no_fields',
+    'custom_storage',
+  ],
+)]
 class FieldStorageConfig extends ConfigEntityBase implements FieldStorageConfigInterface {
 
   /**
diff --git a/core/modules/file/src/Entity/File.php b/core/modules/file/src/Entity/File.php
index c7885e81f369ba92768ae7c3ccbe22efaeb4fc94..0022fec6add1d1137c844ae4391483a74b0626e1 100644
--- a/core/modules/file/src/Entity/File.php
+++ b/core/modules/file/src/Entity/File.php
@@ -2,6 +2,10 @@
 
 namespace Drupal\file\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\ContentEntityDeleteForm;
+use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityChangedTrait;
@@ -9,50 +13,49 @@
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\File\Exception\FileException;
+use Drupal\file\FileAccessControlHandler;
 use Drupal\file\FileInterface;
+use Drupal\file\FileStorage;
+use Drupal\file\FileStorageSchema;
+use Drupal\file\FileViewsData;
 use Drupal\user\EntityOwnerTrait;
 
 /**
  * Defines the file entity class.
  *
  * @ingroup file
- *
- * @ContentEntityType(
- *   id = "file",
- *   label = @Translation("File"),
- *   label_collection = @Translation("Files"),
- *   label_singular = @Translation("file"),
- *   label_plural = @Translation("files"),
- *   label_count = @PluralTranslation(
- *     singular = "@count file",
- *     plural = "@count files",
- *   ),
- *   handlers = {
- *     "storage" = "Drupal\file\FileStorage",
- *     "storage_schema" = "Drupal\file\FileStorageSchema",
- *     "access" = "Drupal\file\FileAccessControlHandler",
- *     "views_data" = "Drupal\file\FileViewsData",
- *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
- *     "form" = {
- *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\file\Entity\FileRouteProvider",
- *     },
- *   },
- *   base_table = "file_managed",
- *   entity_keys = {
- *     "id" = "fid",
- *     "label" = "filename",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "owner" = "uid",
- *   },
- *   links = {
- *     "delete-form" = "/file/{file}/delete",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'file',
+  label: new TranslatableMarkup('File'),
+  label_collection: new TranslatableMarkup('Files'),
+  label_singular: new TranslatableMarkup('file'),
+  label_plural: new TranslatableMarkup('files'),
+  entity_keys: [
+    'id' => 'fid',
+    'label' => 'filename',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'owner' => 'uid',
+  ],
+  handlers: [
+    'storage' => FileStorage::class,
+    'storage_schema' => FileStorageSchema::class,
+    'access' => FileAccessControlHandler::class,
+    'views_data' => FileViewsData::class,
+    'list_builder' => EntityListBuilder::class,
+    'form' => ['delete' => ContentEntityDeleteForm::class],
+    'route_provider' => ['html' => FileRouteProvider::class],
+  ],
+  links: [
+    'delete-form' => '/file/{file}/delete',
+  ],
+  base_table: 'file_managed',
+  label_count: [
+    'singular' => '@count file',
+    'plural' => '@count files',
+  ],
+)]
 class File extends ContentEntityBase implements FileInterface {
 
   use EntityChangedTrait;
diff --git a/core/modules/filter/src/Entity/FilterFormat.php b/core/modules/filter/src/Entity/FilterFormat.php
index e8710b60288284fc31b5acf588952f1d2bdfcf6c..a11dc4386218b660b21a5b01027c18287c735d35 100644
--- a/core/modules/filter/src/Entity/FilterFormat.php
+++ b/core/modules/filter/src/Entity/FilterFormat.php
@@ -3,62 +3,67 @@
 namespace Drupal\filter\Entity;
 
 use Drupal\Component\Plugin\PluginInspectionInterface;
-
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\filter\FilterFormatAccessControlHandler;
+use Drupal\filter\FilterFormatAddForm;
+use Drupal\filter\FilterFormatEditForm;
 use Drupal\filter\FilterFormatInterface;
+use Drupal\filter\FilterFormatListBuilder;
 use Drupal\filter\FilterPluginCollection;
+use Drupal\filter\Form\FilterDisableForm;
+use Drupal\filter\Form\FilterEnableForm;
 use Drupal\filter\Plugin\FilterInterface;
 use Drupal\user\Entity\Role;
 
 /**
  * Represents a text format.
- *
- * @ConfigEntityType(
- *   id = "filter_format",
- *   label = @Translation("Text format"),
- *   label_collection = @Translation("Text formats"),
- *   label_singular = @Translation("text format"),
- *   label_plural = @Translation("text formats"),
- *   label_count = @PluralTranslation(
- *     singular = "@count text format",
- *     plural = "@count text formats",
- *   ),
- *   handlers = {
- *     "form" = {
- *       "add" = "Drupal\filter\FilterFormatAddForm",
- *       "edit" = "Drupal\filter\FilterFormatEditForm",
- *       "disable" = "Drupal\filter\Form\FilterDisableForm",
- *       "enable" = "Drupal\filter\Form\FilterEnableForm",
- *     },
- *     "list_builder" = "Drupal\filter\FilterFormatListBuilder",
- *     "access" = "Drupal\filter\FilterFormatAccessControlHandler",
- *   },
- *   config_prefix = "format",
- *   admin_permission = "administer filters",
- *   entity_keys = {
- *     "id" = "format",
- *     "label" = "name",
- *     "weight" = "weight",
- *     "status" = "status"
- *   },
- *   links = {
- *     "edit-form" = "/admin/config/content/formats/manage/{filter_format}",
- *     "disable" = "/admin/config/content/formats/manage/{filter_format}/disable",
- *     "enable" = "/admin/config/content/formats/manage/{filter_format}/enable",
- *   },
- *   config_export = {
- *     "name",
- *     "format",
- *     "weight",
- *     "roles",
- *     "filters",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'filter_format',
+  label: new TranslatableMarkup('Text format'),
+  label_collection: new TranslatableMarkup('Text formats'),
+  label_singular: new TranslatableMarkup('text format'),
+  label_plural: new TranslatableMarkup('text formats'),
+  config_prefix: 'format',
+  entity_keys: [
+    'id' => 'format',
+    'label' => 'name',
+    'weight' => 'weight',
+    'status' => 'status',
+  ],
+  handlers: [
+    'form' => [
+      'add' => FilterFormatAddForm::class,
+      'edit' => FilterFormatEditForm::class,
+      'disable' => FilterDisableForm::class,
+      'enable' => FilterEnableForm::class,
+    ],
+    'list_builder' => FilterFormatListBuilder::class,
+    'access' => FilterFormatAccessControlHandler::class,
+  ],
+  links: [
+    'edit-form' => '/admin/config/content/formats/manage/{filter_format}',
+    'disable' => '/admin/config/content/formats/manage/{filter_format}/disable',
+    'enable' => '/admin/config/content/formats/manage/{filter_format}/enable',
+  ],
+  admin_permission: 'administer filters',
+  label_count: [
+    'singular' => '@count text format',
+    'plural' => '@count text formats',
+  ],
+  config_export: [
+    'name',
+    'format',
+    'weight',
+    'roles',
+    'filters',
+  ],
+)]
 class FilterFormat extends ConfigEntityBase implements FilterFormatInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/image/src/Entity/ImageStyle.php b/core/modules/image/src/Entity/ImageStyle.php
index f975dc10932c30f221464262830c2bb7c79c9e95..735921b000482a66b8dcbb782917a31731650356 100644
--- a/core/modules/image/src/Entity/ImageStyle.php
+++ b/core/modules/image/src/Entity/ImageStyle.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\image\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
@@ -15,57 +16,62 @@
 use Drupal\Core\StreamWrapper\StreamWrapperManager;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\image\Form\ImageStyleAddForm;
+use Drupal\image\Form\ImageStyleDeleteForm;
+use Drupal\image\Form\ImageStyleEditForm;
+use Drupal\image\Form\ImageStyleFlushForm;
 use Drupal\image\ImageEffectPluginCollection;
 use Drupal\image\ImageEffectInterface;
 use Drupal\image\ImageStyleInterface;
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\StreamWrapper\StreamWrapperInterface;
+use Drupal\image\ImageStyleListBuilder;
+use Drupal\image\ImageStyleStorage;
 use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
 use Drupal\Core\Entity\Entity\EntityViewDisplay;
 
 /**
  * Defines an image style configuration entity.
- *
- * @ConfigEntityType(
- *   id = "image_style",
- *   label = @Translation("Image style"),
- *   label_collection = @Translation("Image styles"),
- *   label_singular = @Translation("image style"),
- *   label_plural = @Translation("image styles"),
- *   label_count = @PluralTranslation(
- *     singular = "@count image style",
- *     plural = "@count image styles",
- *   ),
- *   handlers = {
- *     "form" = {
- *       "add" = "Drupal\image\Form\ImageStyleAddForm",
- *       "edit" = "Drupal\image\Form\ImageStyleEditForm",
- *       "delete" = "Drupal\image\Form\ImageStyleDeleteForm",
- *       "flush" = "Drupal\image\Form\ImageStyleFlushForm"
- *     },
- *     "list_builder" = "Drupal\image\ImageStyleListBuilder",
- *     "storage" = "Drupal\image\ImageStyleStorage",
- *   },
- *   admin_permission = "administer image styles",
- *   config_prefix = "style",
- *   entity_keys = {
- *     "id" = "name",
- *     "label" = "label"
- *   },
- *   links = {
- *     "flush-form" = "/admin/config/media/image-styles/manage/{image_style}/flush",
- *     "edit-form" = "/admin/config/media/image-styles/manage/{image_style}",
- *     "delete-form" = "/admin/config/media/image-styles/manage/{image_style}/delete",
- *     "collection" = "/admin/config/media/image-styles",
- *   },
- *   config_export = {
- *     "name",
- *     "label",
- *     "effects",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'image_style',
+  label: new TranslatableMarkup('Image style'),
+  label_collection: new TranslatableMarkup('Image styles'),
+  label_singular: new TranslatableMarkup('image style'),
+  label_plural: new TranslatableMarkup('image styles'),
+  config_prefix: 'style',
+  entity_keys: [
+    'id' => 'name',
+    'label' => 'label',
+  ],
+  handlers: [
+    'form' => [
+      'add' => ImageStyleAddForm::class,
+      'edit' => ImageStyleEditForm::class,
+      'delete' => ImageStyleDeleteForm::class,
+      'flush' => ImageStyleFlushForm::class,
+    ],
+    'list_builder' => ImageStyleListBuilder::class,
+    'storage' => ImageStyleStorage::class,
+  ],
+  links: [
+    'flush-form' => '/admin/config/media/image-styles/manage/{image_style}/flush',
+    'edit-form' => '/admin/config/media/image-styles/manage/{image_style}',
+    'delete-form' => '/admin/config/media/image-styles/manage/{image_style}/delete',
+    'collection' => '/admin/config/media/image-styles',
+  ],
+  admin_permission: 'administer image styles',
+  label_count: [
+    'singular' => '@count image style',
+    'plural' => '@count image styles',
+  ],
+  config_export: [
+    'name',
+    'label',
+    'effects',
+  ],
+)]
 class ImageStyle extends ConfigEntityBase implements ImageStyleInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/language/src/Entity/ConfigurableLanguage.php b/core/modules/language/src/Entity/ConfigurableLanguage.php
index 6a5681079b9e711784af7881cd4884b54ef9f998..9ac8c9a0839ff8c054c8dfde05069242d3e579f8 100644
--- a/core/modules/language/src/Entity/ConfigurableLanguage.php
+++ b/core/modules/language/src/Entity/ConfigurableLanguage.php
@@ -4,6 +4,7 @@
 
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Language\LanguageManager;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
@@ -11,50 +12,53 @@
 use Drupal\language\ConfigurableLanguageManagerInterface;
 use Drupal\language\Exception\DeleteDefaultLanguageException;
 use Drupal\language\ConfigurableLanguageInterface;
+use Drupal\language\Form\LanguageAddForm;
+use Drupal\language\Form\LanguageDeleteForm;
+use Drupal\language\Form\LanguageEditForm;
+use Drupal\language\LanguageAccessControlHandler;
+use Drupal\language\LanguageListBuilder;
 
 /**
  * Defines the ConfigurableLanguage entity.
- *
- * @ConfigEntityType(
- *   id = "configurable_language",
- *   label = @Translation("Language"),
- *   label_collection = @Translation("Languages"),
- *   label_singular = @Translation("language"),
- *   label_plural = @Translation("languages"),
- *   label_count = @PluralTranslation(
- *     singular = "@count language",
- *     plural = "@count languages",
- *   ),
- *   handlers = {
- *     "list_builder" = "Drupal\language\LanguageListBuilder",
- *     "access" = "Drupal\language\LanguageAccessControlHandler",
- *     "form" = {
- *       "add" = "Drupal\language\Form\LanguageAddForm",
- *       "edit" = "Drupal\language\Form\LanguageEditForm",
- *       "delete" = "Drupal\language\Form\LanguageDeleteForm"
- *     }
- *   },
- *   admin_permission = "administer languages",
- *   config_prefix = "entity",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "weight" = "weight"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "direction",
- *     "weight",
- *     "locked"
- *   },
- *   links = {
- *     "delete-form" = "/admin/config/regional/language/delete/{configurable_language}",
- *     "edit-form" = "/admin/config/regional/language/edit/{configurable_language}",
- *     "collection" = "/admin/config/regional/language",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'configurable_language',
+  label: new TranslatableMarkup('Language'),
+  label_collection: new TranslatableMarkup('Languages'),
+  label_singular: new TranslatableMarkup('language'),
+  label_plural: new TranslatableMarkup('languages'),
+  config_prefix: 'entity',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'weight' => 'weight',
+  ], handlers: [
+    'list_builder' => LanguageListBuilder::class,
+    'access' => LanguageAccessControlHandler::class,
+    'form' => [
+      'add' => LanguageAddForm::class,
+      'edit' => LanguageEditForm::class,
+      'delete' => LanguageDeleteForm::class,
+    ],
+  ],
+  links: [
+    'delete-form' => '/admin/config/regional/language/delete/{configurable_language}',
+    'edit-form' => '/admin/config/regional/language/edit/{configurable_language}',
+    'collection' => '/admin/config/regional/language',
+  ],
+  admin_permission: 'administer languages',
+  label_count: [
+    'singular' => '@count language',
+    'plural' => '@count languages',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'direction',
+    'weight',
+    'locked',
+  ],
+)]
 class ConfigurableLanguage extends ConfigEntityBase implements ConfigurableLanguageInterface {
 
   /**
diff --git a/core/modules/language/src/Entity/ContentLanguageSettings.php b/core/modules/language/src/Entity/ContentLanguageSettings.php
index 72f554a0a0537f4060352d62ceb84f5b9d47d432..f2b1f7d19239ad232302f1397793b58d60089dd6 100644
--- a/core/modules/language/src/Entity/ContentLanguageSettings.php
+++ b/core/modules/language/src/Entity/ContentLanguageSettings.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\language\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Language\LanguageInterface;
@@ -10,35 +12,39 @@
 
 /**
  * Defines the ContentLanguageSettings entity.
- *
- * @ConfigEntityType(
- *   id = "language_content_settings",
- *   label = @Translation("Content language settings"),
- *   label_collection = @Translation("Content language settings"),
- *   label_singular = @Translation("content language setting"),
- *   label_plural = @Translation("content languages settings"),
- *   label_count = @PluralTranslation(
- *     singular = "@count content language setting",
- *     plural = "@count content languages settings",
- *   ),
- *   admin_permission = "administer languages",
- *   config_prefix = "content_settings",
- *   entity_keys = {
- *     "id" = "id"
- *   },
- *   config_export = {
- *     "id",
- *     "target_entity_type_id",
- *     "target_bundle",
- *     "default_langcode",
- *     "language_alterable",
- *   },
- *   list_cache_tags = { "rendered" },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "target_entity_type_id", "target_bundle"},
- *   },
- * )
  */
+#[ConfigEntityType(
+  id: 'language_content_settings',
+  label: new TranslatableMarkup('Content language settings'),
+  label_collection: new TranslatableMarkup('Content language settings'),
+  label_singular: new TranslatableMarkup('content language setting'),
+  label_plural: new TranslatableMarkup('content languages settings'),
+  config_prefix: 'content_settings',
+  entity_keys: [
+    'id' => 'id',
+  ],
+  admin_permission: 'administer languages',
+  label_count: [
+    'singular' => '@count content language setting',
+    'plural' => '@count content languages settings',
+  ],
+  list_cache_tags: [
+    'rendered',
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'target_entity_type_id',
+      'target_bundle',
+    ],
+  ],
+  config_export: [
+    'id',
+    'target_entity_type_id',
+    'target_bundle',
+    'default_langcode',
+    'language_alterable',
+  ])]
 class ContentLanguageSettings extends ConfigEntityBase implements ContentLanguageSettingsInterface {
 
   /**
diff --git a/core/modules/language/tests/language_test/src/Entity/NoLanguageEntityTest.php b/core/modules/language/tests/language_test/src/Entity/NoLanguageEntityTest.php
index 4f8c07993ded1bff7ade2f64876f305551001970..93711536b37bb975fb725be382dab9aea607e325 100644
--- a/core/modules/language/tests/language_test/src/Entity/NoLanguageEntityTest.php
+++ b/core/modules/language/tests/language_test/src/Entity/NoLanguageEntityTest.php
@@ -4,27 +4,29 @@
 
 namespace Drupal\language_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "no_language_entity_test",
- *   label = @Translation("Test entity without language support"),
- *   handlers = {
- *     "views_data" = "Drupal\entity_test\EntityTestViewsData"
- *   },
- *   base_table = "no_language_entity_test",
- *   persistent_cache = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'no_language_entity_test',
+  label: new TranslatableMarkup('Test entity without language support'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+  ],
+  handlers: [
+    'views_data' => EntityTestViewsData::class,
+  ],
+  base_table: 'no_language_entity_test'
+)]
 class NoLanguageEntityTest extends ContentEntityBase {
 
   /**
diff --git a/core/modules/media/src/Entity/Media.php b/core/modules/media/src/Entity/Media.php
index 7fcf32b94cdae3e500dc1d5cfa8d4c9f22d8b69c..87204415f41bafcc28b18c73ae63af1514fd9aaa 100644
--- a/core/modules/media/src/Entity/Media.php
+++ b/core/modules/media/src/Entity/Media.php
@@ -2,14 +2,28 @@
 
 namespace Drupal\media\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\ContentEntityDeleteForm;
+use Drupal\Core\Entity\EntityViewBuilder;
+use Drupal\Core\Entity\Form\DeleteMultipleForm;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EditorialContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\media\MediaAccessControlHandler;
+use Drupal\media\MediaForm;
 use Drupal\media\MediaInterface;
+use Drupal\media\MediaListBuilder;
 use Drupal\media\MediaSourceEntityConstraintsInterface;
 use Drupal\media\MediaSourceFieldConstraintsInterface;
+use Drupal\media\MediaStorage;
+use Drupal\media\MediaViewsData;
+use Drupal\media\Routing\MediaRouteProvider;
 use Drupal\user\EntityOwnerTrait;
 
 /**
@@ -17,78 +31,76 @@
  *
  * @todo Remove default/fallback entity form operation when #2006348 is done.
  * @see https://www.drupal.org/node/2006348.
- *
- * @ContentEntityType(
- *   id = "media",
- *   label = @Translation("Media"),
- *   label_singular = @Translation("media item"),
- *   label_plural = @Translation("media items"),
- *   label_count = @PluralTranslation(
- *     singular = "@count media item",
- *     plural = "@count media items"
- *   ),
- *   bundle_label = @Translation("Media type"),
- *   handlers = {
- *     "storage" = "Drupal\media\MediaStorage",
- *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
- *     "list_builder" = "Drupal\media\MediaListBuilder",
- *     "access" = "Drupal\media\MediaAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\media\MediaForm",
- *       "add" = "Drupal\media\MediaForm",
- *       "edit" = "Drupal\media\MediaForm",
- *       "delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
- *       "delete-multiple-confirm" = "Drupal\Core\Entity\Form\DeleteMultipleForm",
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "views_data" = "Drupal\media\MediaViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\media\Routing\MediaRouteProvider",
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     }
- *   },
- *   base_table = "media",
- *   data_table = "media_field_data",
- *   revision_table = "media_revision",
- *   revision_data_table = "media_field_revision",
- *   translatable = TRUE,
- *   show_revision_ui = TRUE,
- *   entity_keys = {
- *     "id" = "mid",
- *     "revision" = "vid",
- *     "bundle" = "bundle",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "published" = "status",
- *     "owner" = "uid",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message",
- *   },
- *   bundle_entity_type = "media_type",
- *   permission_granularity = "bundle",
- *   admin_permission = "administer media",
- *   field_ui_base_route = "entity.media_type.edit_form",
- *   common_reference_target = TRUE,
- *   links = {
- *     "add-page" = "/media/add",
- *     "add-form" = "/media/add/{media_type}",
- *     "canonical" = "/media/{media}/edit",
- *     "collection" = "/admin/content/media",
- *     "delete-form" = "/media/{media}/delete",
- *     "delete-multiple-form" = "/media/delete",
- *     "edit-form" = "/media/{media}/edit",
- *     "revision" = "/media/{media}/revisions/{media_revision}/view",
- *     "revision-delete-form" = "/media/{media}/revision/{media_revision}/delete",
- *     "revision-revert-form" = "/media/{media}/revision/{media_revision}/revert",
- *     "version-history" = "/media/{media}/revisions",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'media',
+  label: new TranslatableMarkup('Media'),
+  label_singular: new TranslatableMarkup('media item'),
+  label_plural: new TranslatableMarkup('media items'),
+  entity_keys: [
+    'id' => 'mid',
+    'revision' => 'vid',
+    'bundle' => 'bundle',
+    'label' => 'name',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'published' => 'status',
+    'owner' => 'uid',
+  ],
+  handlers: [
+    'storage' => MediaStorage::class,
+    'view_builder' => EntityViewBuilder::class,
+    'list_builder' => MediaListBuilder::class,
+    'access' => MediaAccessControlHandler::class,
+    'form' => [
+      'default' => MediaForm::class,
+      'add' => MediaForm::class,
+      'edit' => MediaForm::class,
+      'delete' => ContentEntityDeleteForm::class,
+      'delete-multiple-confirm' => DeleteMultipleForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'views_data' => MediaViewsData::class,
+    'route_provider' => [
+      'html' => MediaRouteProvider::class,
+      'revision' => RevisionHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-page' => '/media/add',
+    'add-form' => '/media/add/{media_type}',
+    'canonical' => '/media/{media}/edit',
+    'collection' => '/admin/content/media',
+    'delete-form' => '/media/{media}/delete',
+    'delete-multiple-form' => '/media/delete',
+    'edit-form' => '/media/{media}/edit',
+    'revision' => '/media/{media}/revisions/{media_revision}/view',
+    'revision-delete-form' => '/media/{media}/revision/{media_revision}/delete',
+    'revision-revert-form' => '/media/{media}/revision/{media_revision}/revert',
+    'version-history' => '/media/{media}/revisions',
+  ],
+  admin_permission: 'administer media',
+  permission_granularity: 'bundle',
+  bundle_entity_type: 'media_type',
+  bundle_label: new TranslatableMarkup('Media type'),
+  base_table: 'media',
+  data_table: 'media_field_data',
+  revision_table: 'media_revision',
+  revision_data_table: 'media_field_revision',
+  translatable: TRUE,
+  show_revision_ui: TRUE,
+  label_count: [
+    'singular' => '@count media item',
+    'plural' => '@count media items',
+  ],
+  field_ui_base_route: 'entity.media_type.edit_form',
+  common_reference_target: TRUE,
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ])]
 class Media extends EditorialContentEntityBase implements MediaInterface {
 
   use EntityOwnerTrait;
diff --git a/core/modules/media/src/Entity/MediaType.php b/core/modules/media/src/Entity/MediaType.php
index e80b2d3a1a38456fcde793c645c94b4c1fdc0239..4cfc89e2e15b51a988a28b583daa6f5fc7f9ee42 100644
--- a/core/modules/media/src/Entity/MediaType.php
+++ b/core/modules/media/src/Entity/MediaType.php
@@ -4,69 +4,77 @@
 
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
 use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\media\Form\MediaTypeDeleteConfirmForm;
+use Drupal\media\MediaTypeAccessControlHandler;
+use Drupal\media\MediaTypeForm;
 use Drupal\media\MediaTypeInterface;
+use Drupal\media\MediaTypeListBuilder;
+use Drupal\user\Entity\EntityPermissionsRouteProvider;
 
 /**
  * Defines the Media type configuration entity.
- *
- * @ConfigEntityType(
- *   id = "media_type",
- *   label = @Translation("Media type"),
- *   label_collection = @Translation("Media types"),
- *   label_singular = @Translation("media type"),
- *   label_plural = @Translation("media types"),
- *   label_count = @PluralTranslation(
- *     singular = "@count media type",
- *     plural = "@count media types"
- *   ),
- *   handlers = {
- *     "access" = "Drupal\media\MediaTypeAccessControlHandler",
- *     "form" = {
- *       "add" = "Drupal\media\MediaTypeForm",
- *       "edit" = "Drupal\media\MediaTypeForm",
- *       "delete" = "Drupal\media\Form\MediaTypeDeleteConfirmForm"
- *     },
- *     "list_builder" = "Drupal\media\MediaTypeListBuilder",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *       "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
- *     }
- *   },
- *   admin_permission = "administer media types",
- *   config_prefix = "type",
- *   bundle_of = "media",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "status" = "status",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "description",
- *     "source",
- *     "queue_thumbnail_downloads",
- *     "new_revision",
- *     "source_configuration",
- *     "field_map",
- *     "status",
- *   },
- *   links = {
- *     "add-form" = "/admin/structure/media/add",
- *     "edit-form" = "/admin/structure/media/manage/{media_type}",
- *     "delete-form" = "/admin/structure/media/manage/{media_type}/delete",
- *     "entity-permissions-form" = "/admin/structure/media/manage/{media_type}/permissions",
- *     "collection" = "/admin/structure/media",
- *   },
- *   constraints = {
- *     "ImmutableProperties" = {"id", "source"},
- *     "MediaMappingsConstraint" = { },
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'media_type',
+  label: new TranslatableMarkup('Media type'),
+  label_collection: new TranslatableMarkup('Media types'),
+  label_singular: new TranslatableMarkup('media type'),
+  label_plural: new TranslatableMarkup('media types'),
+  config_prefix: 'type',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'status' => 'status',
+  ],
+  handlers: [
+    'access' => MediaTypeAccessControlHandler::class,
+    'form' => [
+      'add' => MediaTypeForm::class,
+      'edit' => MediaTypeForm::class,
+      'delete' => MediaTypeDeleteConfirmForm::class,
+    ],
+    'list_builder' => MediaTypeListBuilder::class,
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+      'permissions' => EntityPermissionsRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/admin/structure/media/add',
+    'edit-form' => '/admin/structure/media/manage/{media_type}',
+    'delete-form' => '/admin/structure/media/manage/{media_type}/delete',
+    'entity-permissions-form' => '/admin/structure/media/manage/{media_type}/permissions',
+    'collection' => '/admin/structure/media',
+  ],
+  admin_permission: 'administer media types',
+  bundle_of: 'media',
+  label_count: [
+    'singular' => '@count media type',
+    'plural' => '@count media types',
+  ],
+  constraints: [
+    'ImmutableProperties' => [
+      'id',
+      'source',
+    ],
+    'MediaMappingsConstraint' => [],
+  ],
+  config_export: [
+    'id',
+    'label',
+    'description',
+    'source',
+    'queue_thumbnail_downloads',
+    'new_revision',
+    'source_configuration',
+    'field_map',
+    'status',
+  ])]
 class MediaType extends ConfigEntityBundleBase implements MediaTypeInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
index db378d8559bfef14fd47b454137a354e52c593a6..28503a01c07ffc61126474a434a9187e29cca1c9 100644
--- a/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
+++ b/core/modules/menu_link_content/src/Entity/MenuLinkContent.php
@@ -2,69 +2,75 @@
 
 namespace Drupal\menu_link_content\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EditorialContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\link\LinkItemInterface;
+use Drupal\menu_link_content\Form\MenuLinkContentDeleteForm;
+use Drupal\menu_link_content\Form\MenuLinkContentForm;
+use Drupal\menu_link_content\MenuLinkContentAccessControlHandler;
 use Drupal\menu_link_content\MenuLinkContentInterface;
+use Drupal\menu_link_content\MenuLinkContentStorage;
+use Drupal\menu_link_content\MenuLinkContentStorageSchema;
+use Drupal\menu_link_content\MenuLinkListBuilder;
 
 /**
  * Defines the menu link content entity class.
  *
  * @property \Drupal\Core\Field\FieldItemList $link
  * @property \Drupal\Core\Field\FieldItemList $rediscover
- *
- * @ContentEntityType(
- *   id = "menu_link_content",
- *   label = @Translation("Custom menu link"),
- *   label_collection = @Translation("Custom menu links"),
- *   label_singular = @Translation("custom menu link"),
- *   label_plural = @Translation("custom menu links"),
- *   label_count = @PluralTranslation(
- *     singular = "@count custom menu link",
- *     plural = "@count custom menu links",
- *   ),
- *   handlers = {
- *     "storage" = "\Drupal\menu_link_content\MenuLinkContentStorage",
- *     "storage_schema" = "Drupal\menu_link_content\MenuLinkContentStorageSchema",
- *     "access" = "Drupal\menu_link_content\MenuLinkContentAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\menu_link_content\Form\MenuLinkContentForm",
- *       "delete" = "Drupal\menu_link_content\Form\MenuLinkContentDeleteForm"
- *     },
- *     "list_builder" = "Drupal\menu_link_content\MenuLinkListBuilder"
- *   },
- *   admin_permission = "administer menu",
- *   base_table = "menu_link_content",
- *   data_table = "menu_link_content_data",
- *   revision_table = "menu_link_content_revision",
- *   revision_data_table = "menu_link_content_field_revision",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "revision_id",
- *     "label" = "title",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "bundle" = "bundle",
- *     "published" = "enabled",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message",
- *   },
- *   links = {
- *     "canonical" = "/admin/structure/menu/item/{menu_link_content}/edit",
- *     "edit-form" = "/admin/structure/menu/item/{menu_link_content}/edit",
- *     "delete-form" = "/admin/structure/menu/item/{menu_link_content}/delete",
- *   },
- *   constraints = {
- *     "MenuTreeHierarchy" = {}
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'menu_link_content',
+  label: new TranslatableMarkup('Custom menu link'),
+  label_collection: new TranslatableMarkup('Custom menu links'),
+  label_singular: new TranslatableMarkup('custom menu link'),
+  label_plural: new TranslatableMarkup('custom menu links'),
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'revision_id',
+    'label' => 'title',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'bundle' => 'bundle',
+    'published' => 'enabled',
+  ],
+  handlers: [
+    'storage' => MenuLinkContentStorage::class,
+    'storage_schema' => MenuLinkContentStorageSchema::class,
+    'access' => MenuLinkContentAccessControlHandler::class,
+    'form' => [
+      'default' => MenuLinkContentForm::class,
+      'delete' => MenuLinkContentDeleteForm::class,
+    ],
+    'list_builder' => MenuLinkListBuilder::class,
+  ],
+  links: [
+    'canonical' => '/admin/structure/menu/item/{menu_link_content}/edit',
+    'edit-form' => '/admin/structure/menu/item/{menu_link_content}/edit',
+    'delete-form' => '/admin/structure/menu/item/{menu_link_content}/delete',
+  ],
+  admin_permission: 'administer menu',
+  base_table: 'menu_link_content',
+  data_table: 'menu_link_content_data',
+  revision_table: 'menu_link_content_revision',
+  revision_data_table: 'menu_link_content_field_revision',
+  translatable: TRUE,
+  label_count: [
+    'singular' => '@count custom menu link',
+    'plural' => '@count custom menu links',
+  ],
+  constraints: [
+    'MenuTreeHierarchy' => [],
+  ],
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ])]
 class MenuLinkContent extends EditorialContentEntityBase implements MenuLinkContentInterface {
 
   /**
diff --git a/core/modules/migrate/tests/modules/migrate_entity_test/src/Entity/StringIdEntityTest.php b/core/modules/migrate/tests/modules/migrate_entity_test/src/Entity/StringIdEntityTest.php
index 8523c8ea4da940dd310c5db10433f83011583f56..3fd96f44bccf5302d31657b567e26ea454419cd0 100644
--- a/core/modules/migrate/tests/modules/migrate_entity_test/src/Entity/StringIdEntityTest.php
+++ b/core/modules/migrate/tests/modules/migrate_entity_test/src/Entity/StringIdEntityTest.php
@@ -4,22 +4,23 @@
 
 namespace Drupal\migrate_entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 
 /**
  * Defines a content entity type that has a string ID.
- *
- * @ContentEntityType(
- *   id = "migrate_string_id_entity_test",
- *   label = @Translation("String id entity test"),
- *   base_table = "migrate_entity_test_string_id",
- *   entity_keys = {
- *     "id" = "id",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'migrate_string_id_entity_test',
+  label: new TranslatableMarkup('String id entity test'),
+  entity_keys: [
+    'id' => 'id',
+  ],
+  base_table: 'migrate_entity_test_string_id',
+)]
 class StringIdEntityTest extends ContentEntityBase {
 
   /**
diff --git a/core/modules/node/src/Entity/Node.php b/core/modules/node/src/Entity/Node.php
index b907ed608bc18c4483d7f577c95a77ecf9617496..1c6d9d9bae87f84af21b067bb743515d64691d47 100644
--- a/core/modules/node/src/Entity/Node.php
+++ b/core/modules/node/src/Entity/Node.php
@@ -2,86 +2,97 @@
 
 namespace Drupal\node\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
 use Drupal\Core\Entity\EditorialContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\node\Form\DeleteMultiple;
+use Drupal\node\Form\NodeDeleteForm;
+use Drupal\node\NodeAccessControlHandler;
+use Drupal\node\NodeForm;
 use Drupal\node\NodeInterface;
+use Drupal\node\NodeListBuilder;
+use Drupal\node\NodeStorage;
+use Drupal\node\NodeStorageSchema;
+use Drupal\node\NodeTranslationHandler;
+use Drupal\node\NodeViewBuilder;
+use Drupal\node\NodeViewsData;
 use Drupal\user\EntityOwnerTrait;
 
 /**
  * Defines the node entity class.
- *
- * @ContentEntityType(
- *   id = "node",
- *   label = @Translation("Content"),
- *   label_collection = @Translation("Content"),
- *   label_singular = @Translation("content item"),
- *   label_plural = @Translation("content items"),
- *   label_count = @PluralTranslation(
- *     singular = "@count content item",
- *     plural = "@count content items"
- *   ),
- *   bundle_label = @Translation("Content type"),
- *   handlers = {
- *     "storage" = "Drupal\node\NodeStorage",
- *     "storage_schema" = "Drupal\node\NodeStorageSchema",
- *     "view_builder" = "Drupal\node\NodeViewBuilder",
- *     "access" = "Drupal\node\NodeAccessControlHandler",
- *     "views_data" = "Drupal\node\NodeViewsData",
- *     "form" = {
- *       "default" = "Drupal\node\NodeForm",
- *       "delete" = "Drupal\node\Form\NodeDeleteForm",
- *       "edit" = "Drupal\node\NodeForm",
- *       "delete-multiple-confirm" = "Drupal\node\Form\DeleteMultiple"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\node\Entity\NodeRouteProvider",
- *     },
- *     "list_builder" = "Drupal\node\NodeListBuilder",
- *     "translation" = "Drupal\node\NodeTranslationHandler"
- *   },
- *   base_table = "node",
- *   data_table = "node_field_data",
- *   revision_table = "node_revision",
- *   revision_data_table = "node_field_revision",
- *   show_revision_ui = TRUE,
- *   translatable = TRUE,
- *   list_cache_contexts = { "user.node_grants:view" },
- *   entity_keys = {
- *     "id" = "nid",
- *     "revision" = "vid",
- *     "bundle" = "type",
- *     "label" = "title",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "status" = "status",
- *     "published" = "status",
- *     "uid" = "uid",
- *     "owner" = "uid",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_uid",
- *     "revision_created" = "revision_timestamp",
- *     "revision_log_message" = "revision_log"
- *   },
- *   bundle_entity_type = "node_type",
- *   field_ui_base_route = "entity.node_type.edit_form",
- *   common_reference_target = TRUE,
- *   permission_granularity = "bundle",
- *   collection_permission = "access content overview",
- *   links = {
- *     "canonical" = "/node/{node}",
- *     "delete-form" = "/node/{node}/delete",
- *     "delete-multiple-form" = "/admin/content/node/delete",
- *     "edit-form" = "/node/{node}/edit",
- *     "version-history" = "/node/{node}/revisions",
- *     "revision" = "/node/{node}/revisions/{node_revision}/view",
- *     "create" = "/node",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'node',
+  label: new TranslatableMarkup('Content'),
+  label_collection: new TranslatableMarkup('Content'),
+  label_singular: new TranslatableMarkup('content item'),
+  label_plural: new TranslatableMarkup('content items'),
+  entity_keys: [
+    'id' => 'nid',
+    'revision' => 'vid',
+    'bundle' => 'type',
+    'label' => 'title',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'status' => 'status',
+    'published' => 'status',
+    'uid' => 'uid',
+    'owner' => 'uid',
+  ],
+  handlers: [
+    'storage' => NodeStorage::class,
+    'storage_schema' => NodeStorageSchema::class,
+    'view_builder' => NodeViewBuilder::class,
+    'access' => NodeAccessControlHandler::class,
+    'views_data' => NodeViewsData::class,
+    'form' => [
+      'default' => NodeForm::class,
+      'delete' => NodeDeleteForm::class,
+      'edit' => NodeForm::class,
+      'delete-multiple-confirm' => DeleteMultiple::class,
+    ],
+    'route_provider' => [
+      'html' => NodeRouteProvider::class,
+    ],
+    'list_builder' => NodeListBuilder::class,
+    'translation' => NodeTranslationHandler::class,
+  ],
+  links: [
+    'canonical' => '/node/{node}',
+    'delete-form' => '/node/{node}/delete',
+    'delete-multiple-form' => '/admin/content/node/delete',
+    'edit-form' => '/node/{node}/edit',
+    'version-history' => '/node/{node}/revisions',
+    'revision' => '/node/{node}/revisions/{node_revision}/view',
+    'create' => '/node',
+  ],
+  collection_permission: 'access content overview',
+  permission_granularity: 'bundle',
+  bundle_entity_type: 'node_type',
+  bundle_label: new TranslatableMarkup('Content type'),
+  base_table: 'node',
+  data_table: 'node_field_data',
+  revision_table: 'node_revision',
+  revision_data_table: 'node_field_revision',
+  translatable: TRUE,
+  show_revision_ui: TRUE,
+  label_count: [
+    'singular' => '@count content item',
+    'plural' => '@count content items',
+  ],
+  field_ui_base_route: 'entity.node_type.edit_form',
+  common_reference_target: TRUE,
+  list_cache_contexts: ['user.node_grants:view'],
+  revision_metadata_keys: [
+    'revision_user' => 'revision_uid',
+    'revision_created' => 'revision_timestamp',
+    'revision_log_message' => 'revision_log',
+  ],
+)]
 class Node extends EditorialContentEntityBase implements NodeInterface {
 
   use EntityOwnerTrait;
diff --git a/core/modules/node/src/Entity/NodeType.php b/core/modules/node/src/Entity/NodeType.php
index 934b4a2c38597b3dd936d93229b695628d42cefc..949b088fe963b6cfe3a36b7f564bf04eeaf3a45d 100644
--- a/core/modules/node/src/Entity/NodeType.php
+++ b/core/modules/node/src/Entity/NodeType.php
@@ -4,59 +4,64 @@
 
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\node\Form\NodeTypeDeleteConfirm;
+use Drupal\node\NodeTypeAccessControlHandler;
+use Drupal\node\NodeTypeForm;
 use Drupal\node\NodeTypeInterface;
+use Drupal\node\NodeTypeListBuilder;
+use Drupal\user\Entity\EntityPermissionsRouteProvider;
 
 /**
  * Defines the Node type configuration entity.
- *
- * @ConfigEntityType(
- *   id = "node_type",
- *   label = @Translation("Content type"),
- *   label_collection = @Translation("Content types"),
- *   label_singular = @Translation("content type"),
- *   label_plural = @Translation("content types"),
- *   label_count = @PluralTranslation(
- *     singular = "@count content type",
- *     plural = "@count content types",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\node\NodeTypeAccessControlHandler",
- *     "form" = {
- *       "add" = "Drupal\node\NodeTypeForm",
- *       "edit" = "Drupal\node\NodeTypeForm",
- *       "delete" = "Drupal\node\Form\NodeTypeDeleteConfirm"
- *     },
- *     "route_provider" = {
- *       "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
- *     },
- *     "list_builder" = "Drupal\node\NodeTypeListBuilder",
- *   },
- *   admin_permission = "administer content types",
- *   config_prefix = "type",
- *   bundle_of = "node",
- *   entity_keys = {
- *     "id" = "type",
- *     "label" = "name"
- *   },
- *   links = {
- *     "edit-form" = "/admin/structure/types/manage/{node_type}",
- *     "delete-form" = "/admin/structure/types/manage/{node_type}/delete",
- *     "entity-permissions-form" = "/admin/structure/types/manage/{node_type}/permissions",
- *     "collection" = "/admin/structure/types",
- *   },
- *   config_export = {
- *     "name",
- *     "type",
- *     "description",
- *     "help",
- *     "new_revision",
- *     "preview_mode",
- *     "display_submitted",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'node_type',
+  label: new TranslatableMarkup('Content type'),
+  label_collection: new TranslatableMarkup('Content types'),
+  label_singular: new TranslatableMarkup('content type'),
+  label_plural: new TranslatableMarkup('content types'),
+  config_prefix: 'type',
+  entity_keys: [
+    'id' => 'type',
+    'label' => 'name',
+  ],
+  handlers: [
+    'access' => NodeTypeAccessControlHandler::class,
+    'form' => [
+      'add' => NodeTypeForm::class,
+      'edit' => NodeTypeForm::class,
+      'delete' => NodeTypeDeleteConfirm::class,
+    ],
+    'route_provider' => [
+      'permissions' => EntityPermissionsRouteProvider::class,
+    ],
+    'list_builder' => NodeTypeListBuilder::class,
+  ],
+  links: [
+    'edit-form' => '/admin/structure/types/manage/{node_type}',
+    'delete-form' => '/admin/structure/types/manage/{node_type}/delete',
+    'entity-permissions-form' => '/admin/structure/types/manage/{node_type}/permissions',
+    'collection' => '/admin/structure/types',
+  ],
+  admin_permission: 'administer content types',
+  bundle_of: 'node',
+  label_count: [
+    'singular' => '@count content type',
+    'plural' => '@count content types',
+  ],
+  config_export: [
+    'name',
+    'type',
+    'description',
+    'help',
+    'new_revision',
+    'preview_mode',
+    'display_submitted',
+  ],
+)]
 class NodeType extends ConfigEntityBundleBase implements NodeTypeInterface {
 
   /**
diff --git a/core/modules/path_alias/src/Entity/PathAlias.php b/core/modules/path_alias/src/Entity/PathAlias.php
index aabbaaff1e1cae9b1b0aa4f91dd71bc528cb1628..6ace9f070708e494a0c468e0aab598da586f59b6 100644
--- a/core/modules/path_alias/src/Entity/PathAlias.php
+++ b/core/modules/path_alias/src/Entity/PathAlias.php
@@ -2,6 +2,7 @@
 
 namespace Drupal\path_alias\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityPublishedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
@@ -10,40 +11,41 @@
 use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\path_alias\PathAliasInterface;
+use Drupal\path_alias\PathAliasStorage;
+use Drupal\path_alias\PathAliasStorageSchema;
 
 /**
  * Defines the path_alias entity class.
- *
- * @ContentEntityType(
- *   id = "path_alias",
- *   label = @Translation("URL alias"),
- *   label_collection = @Translation("URL aliases"),
- *   label_singular = @Translation("URL alias"),
- *   label_plural = @Translation("URL aliases"),
- *   label_count = @PluralTranslation(
- *     singular = "@count URL alias",
- *     plural = "@count URL aliases"
- *   ),
- *   handlers = {
- *     "storage" = "Drupal\path_alias\PathAliasStorage",
- *     "storage_schema" = "Drupal\path_alias\PathAliasStorageSchema",
- *   },
- *   base_table = "path_alias",
- *   revision_table = "path_alias_revision",
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "revision_id",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "published" = "status",
- *   },
- *   admin_permission = "administer url aliases",
- *   list_cache_tags = { "route_match" },
- *   constraints = {
- *     "UniquePathAlias" = {}
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'path_alias',
+  label: new TranslatableMarkup('URL alias'),
+  label_collection: new TranslatableMarkup('URL aliases'),
+  label_singular: new TranslatableMarkup('URL alias'),
+  label_plural: new TranslatableMarkup('URL aliases'),
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'revision_id',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'published' => 'status',
+  ],
+  handlers: [
+    'storage' => PathAliasStorage::class,
+    'storage_schema' => PathAliasStorageSchema::class,
+  ],
+  admin_permission: 'administer url aliases',
+  base_table: 'path_alias',
+  revision_table: 'path_alias_revision',
+  label_count: [
+    'singular' => '@count URL alias',
+    'plural' => '@count URL aliases',
+  ],
+  list_cache_tags: ['route_match'],
+  constraints: [
+    'UniquePathAlias' => [],
+  ],
+)]
 class PathAlias extends ContentEntityBase implements PathAliasInterface {
 
   use EntityPublishedTrait;
diff --git a/core/modules/responsive_image/src/Entity/ResponsiveImageStyle.php b/core/modules/responsive_image/src/Entity/ResponsiveImageStyle.php
index 31589a64a6511a8434979070ef7a19dc8ff4b7d0..dac2cec20df727200c2a70e98084e59dd8ad86d3 100644
--- a/core/modules/responsive_image/src/Entity/ResponsiveImageStyle.php
+++ b/core/modules/responsive_image/src/Entity/ResponsiveImageStyle.php
@@ -2,53 +2,57 @@
 
 namespace Drupal\responsive_image\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityDeleteForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\image\Entity\ImageStyle;
+use Drupal\responsive_image\ResponsiveImageStyleForm;
 use Drupal\responsive_image\ResponsiveImageStyleInterface;
+use Drupal\responsive_image\ResponsiveImageStyleListBuilder;
 
 /**
  * Defines the responsive image style entity.
- *
- * @ConfigEntityType(
- *   id = "responsive_image_style",
- *   label = @Translation("Responsive image style"),
- *   label_collection = @Translation("Responsive image styles"),
- *   label_singular = @Translation("responsive image style"),
- *   label_plural = @Translation("responsive image styles"),
- *   label_count = @PluralTranslation(
- *     singular = "@count responsive image style",
- *     plural = "@count responsive image styles",
- *   ),
- *   handlers = {
- *     "list_builder" = "Drupal\responsive_image\ResponsiveImageStyleListBuilder",
- *     "form" = {
- *       "edit" = "Drupal\responsive_image\ResponsiveImageStyleForm",
- *       "add" = "Drupal\responsive_image\ResponsiveImageStyleForm",
- *       "delete" = "Drupal\Core\Entity\EntityDeleteForm",
- *       "duplicate" = "Drupal\responsive_image\ResponsiveImageStyleForm"
- *     }
- *   },
- *   admin_permission = "administer responsive images",
- *   config_prefix = "styles",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "image_style_mappings",
- *     "breakpoint_group",
- *     "fallback_image_style",
- *   },
- *   links = {
- *     "edit-form" = "/admin/config/media/responsive-image-style/{responsive_image_style}",
- *     "duplicate-form" = "/admin/config/media/responsive-image-style/{responsive_image_style}/duplicate",
- *     "delete-form" = "/admin/config/media/responsive-image-style/{responsive_image_style}/delete",
- *     "collection" = "/admin/config/media/responsive-image-style",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'responsive_image_style',
+  label: new TranslatableMarkup('Responsive image style'),
+  label_collection: new TranslatableMarkup('Responsive image styles'),
+  label_singular: new TranslatableMarkup('responsive image style'),
+  label_plural: new TranslatableMarkup('responsive image styles'),
+  config_prefix: 'styles',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'list_builder' => ResponsiveImageStyleListBuilder::class,
+    'form' => [
+      'edit' => ResponsiveImageStyleForm::class,
+      'add' => ResponsiveImageStyleForm::class,
+      'delete' => EntityDeleteForm::class,
+      'duplicate' => ResponsiveImageStyleForm::class,
+    ],
+  ],
+  links: [
+    'edit-form' => '/admin/config/media/responsive-image-style/{responsive_image_style}',
+    'duplicate-form' => '/admin/config/media/responsive-image-style/{responsive_image_style}/duplicate',
+    'delete-form' => '/admin/config/media/responsive-image-style/{responsive_image_style}/delete',
+    'collection' => '/admin/config/media/responsive-image-style',
+  ],
+  admin_permission: 'administer responsive images',
+  label_count: [
+    'singular' => '@count responsive image style',
+    'plural' => '@count responsive image styles',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'image_style_mappings',
+    'breakpoint_group',
+    'fallback_image_style',
+  ],
+)]
 class ResponsiveImageStyle extends ConfigEntityBase implements ResponsiveImageStyleInterface {
 
   /**
diff --git a/core/modules/rest/src/Entity/RestResourceConfig.php b/core/modules/rest/src/Entity/RestResourceConfig.php
index 027eb5e6c5f5eec41f4f0e1d059c15df3bdba124..2445fbf4a6d52502d6c42b2c55b0428de9781e82 100644
--- a/core/modules/rest/src/Entity/RestResourceConfig.php
+++ b/core/modules/rest/src/Entity/RestResourceConfig.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\rest\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
@@ -9,30 +11,29 @@
 
 /**
  * Defines a RestResourceConfig configuration entity class.
- *
- * @ConfigEntityType(
- *   id = "rest_resource_config",
- *   label = @Translation("REST resource configuration"),
- *   label_collection = @Translation("REST resource configurations"),
- *   label_singular = @Translation("REST resource configuration"),
- *   label_plural = @Translation("REST resource configurations"),
- *   label_count = @PluralTranslation(
- *     singular = "@count REST resource configuration",
- *     plural = "@count REST resource configurations",
- *   ),
- *   config_prefix = "resource",
- *   admin_permission = "administer rest resources",
- *   entity_keys = {
- *     "id" = "id"
- *   },
- *   config_export = {
- *     "id",
- *     "plugin_id",
- *     "granularity",
- *     "configuration"
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'rest_resource_config',
+  label: new TranslatableMarkup('REST resource configuration'),
+  label_collection: new TranslatableMarkup('REST resource configurations'),
+  label_singular: new TranslatableMarkup('REST resource configuration'),
+  label_plural: new TranslatableMarkup('REST resource configurations'),
+  config_prefix: 'resource',
+  entity_keys: [
+    'id' => 'id',
+  ],
+  admin_permission: 'administer rest resources',
+  label_count: [
+    'singular' => '@count REST resource configuration',
+    'plural' => '@count REST resource configurations',
+  ],
+  config_export: [
+    'id',
+    'plugin_id',
+    'granularity',
+    'configuration',
+  ],
+)]
 class RestResourceConfig extends ConfigEntityBase implements RestResourceConfigInterface {
 
   /**
diff --git a/core/modules/search/src/Entity/SearchPage.php b/core/modules/search/src/Entity/SearchPage.php
index d5eef74a9cf4845d533e46fe2fb6ca8b07d9731a..894da73bbac0259de6c6b8cefc10720ce2a3bfb4 100644
--- a/core/modules/search/src/Entity/SearchPage.php
+++ b/core/modules/search/src/Entity/SearchPage.php
@@ -2,62 +2,68 @@
 
 namespace Drupal\search\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityDeleteForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Config\Entity\ConfigEntityInterface;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
+use Drupal\search\Form\SearchPageAddForm;
+use Drupal\search\Form\SearchPageEditForm;
 use Drupal\search\Plugin\SearchIndexingInterface;
 use Drupal\search\Plugin\SearchPluginCollection;
+use Drupal\search\SearchPageAccessControlHandler;
 use Drupal\search\SearchPageInterface;
+use Drupal\search\SearchPageListBuilder;
 
 /**
  * Defines a configured search page.
- *
- * @ConfigEntityType(
- *   id = "search_page",
- *   label = @Translation("Search page"),
- *   label_collection = @Translation("Search pages"),
- *   label_singular = @Translation("search page"),
- *   label_plural = @Translation("search pages"),
- *   label_count = @PluralTranslation(
- *     singular = "@count search page",
- *     plural = "@count search pages",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\search\SearchPageAccessControlHandler",
- *     "list_builder" = "Drupal\search\SearchPageListBuilder",
- *     "form" = {
- *       "add" = "Drupal\search\Form\SearchPageAddForm",
- *       "edit" = "Drupal\search\Form\SearchPageEditForm",
- *       "delete" = "Drupal\Core\Entity\EntityDeleteForm"
- *     }
- *   },
- *   admin_permission = "administer search",
- *   links = {
- *     "edit-form" = "/admin/config/search/pages/manage/{search_page}",
- *     "delete-form" = "/admin/config/search/pages/manage/{search_page}/delete",
- *     "enable" = "/admin/config/search/pages/manage/{search_page}/enable",
- *     "disable" = "/admin/config/search/pages/manage/{search_page}/disable",
- *     "set-default" = "/admin/config/search/pages/manage/{search_page}/set-default",
- *     "collection" = "/admin/config/search/pages",
- *   },
- *   config_prefix = "page",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "weight" = "weight",
- *     "status" = "status"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "path",
- *     "weight",
- *     "plugin",
- *     "configuration",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'search_page',
+  label: new TranslatableMarkup('Search page'),
+  label_collection: new TranslatableMarkup('Search pages'),
+  label_singular: new TranslatableMarkup('search page'),
+  label_plural: new TranslatableMarkup('search pages'),
+  config_prefix: 'page',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'weight' => 'weight',
+    'status' => 'status',
+  ],
+  handlers: [
+    'access' => SearchPageAccessControlHandler::class,
+    'list_builder' => SearchPageListBuilder::class,
+    'form' => [
+      'add' => SearchPageAddForm::class,
+      'edit' => SearchPageEditForm::class,
+      'delete' => EntityDeleteForm::class,
+    ],
+  ],
+  links: [
+    'edit-form' => '/admin/config/search/pages/manage/{search_page}',
+    'delete-form' => '/admin/config/search/pages/manage/{search_page}/delete',
+    'enable' => '/admin/config/search/pages/manage/{search_page}/enable',
+    'disable' => '/admin/config/search/pages/manage/{search_page}/disable',
+    'set-default' => '/admin/config/search/pages/manage/{search_page}/set-default',
+    'collection' => '/admin/config/search/pages',
+  ],
+  admin_permission: 'administer search',
+  label_count: [
+    'singular' => '@count search page',
+    'plural' => '@count search pages',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'path',
+    'weight',
+    'plugin',
+    'configuration',
+  ],
+)]
 class SearchPage extends ConfigEntityBase implements SearchPageInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/shortcut/src/Entity/Shortcut.php b/core/modules/shortcut/src/Entity/Shortcut.php
index 3d591b3ada3e86e5b95919319dd54e1c3e676d59..826fd5dfeec178a78cb3ed42ff966dfca71c388a 100644
--- a/core/modules/shortcut/src/Entity/Shortcut.php
+++ b/core/modules/shortcut/src/Entity/Shortcut.php
@@ -2,58 +2,64 @@
 
 namespace Drupal\shortcut\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\link\LinkItemInterface;
+use Drupal\shortcut\Form\ShortcutDeleteForm;
+use Drupal\shortcut\ShortcutAccessControlHandler;
+use Drupal\shortcut\ShortcutForm;
 use Drupal\shortcut\ShortcutInterface;
 
 /**
  * Defines the shortcut entity class.
  *
  * @property \Drupal\link\LinkItemInterface $link
- *
- * @ContentEntityType(
- *   id = "shortcut",
- *   label = @Translation("Shortcut link"),
- *   label_collection = @Translation("Shortcut links"),
- *   label_singular = @Translation("shortcut link"),
- *   label_plural = @Translation("shortcut links"),
- *   label_count = @PluralTranslation(
- *     singular = "@count shortcut link",
- *     plural = "@count shortcut links",
- *   ),
- *   bundle_label = @Translation("Shortcut set"),
- *   handlers = {
- *     "access" = "Drupal\shortcut\ShortcutAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\shortcut\ShortcutForm",
- *       "add" = "Drupal\shortcut\ShortcutForm",
- *       "edit" = "Drupal\shortcut\ShortcutForm",
- *       "delete" = "Drupal\shortcut\Form\ShortcutDeleteForm"
- *     },
- *   },
- *   base_table = "shortcut",
- *   data_table = "shortcut_field_data",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "shortcut_set",
- *     "label" = "title",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "canonical" = "/admin/config/user-interface/shortcut/link/{shortcut}",
- *     "delete-form" = "/admin/config/user-interface/shortcut/link/{shortcut}/delete",
- *     "edit-form" = "/admin/config/user-interface/shortcut/link/{shortcut}",
- *   },
- *   list_cache_tags = { "config:shortcut_set_list" },
- *   bundle_entity_type = "shortcut_set"
- * )
  */
+#[ContentEntityType(
+  id: 'shortcut',
+  label: new TranslatableMarkup('Shortcut link'),
+  label_collection: new TranslatableMarkup('Shortcut links'),
+  label_singular: new TranslatableMarkup('shortcut link'),
+  label_plural: new TranslatableMarkup('shortcut links'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'shortcut_set',
+    'label' => 'title',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => ShortcutAccessControlHandler::class,
+    'form' => [
+      'default' => ShortcutForm::class,
+      'add' => ShortcutForm::class,
+      'edit' => ShortcutForm::class,
+      'delete' => ShortcutDeleteForm::class,
+    ],
+  ],
+  links: [
+    'canonical' => '/admin/config/user-interface/shortcut/link/{shortcut}',
+    'delete-form' => '/admin/config/user-interface/shortcut/link/{shortcut}/delete',
+    'edit-form' => '/admin/config/user-interface/shortcut/link/{shortcut}',
+  ],
+  bundle_entity_type: 'shortcut_set',
+  bundle_label: new TranslatableMarkup('Shortcut set'),
+  base_table: 'shortcut',
+  data_table: 'shortcut_field_data',
+  translatable: TRUE,
+  label_count: [
+    'singular' => '@count shortcut link',
+    'plural' => '@count shortcut links',
+  ],
+  list_cache_tags: [
+    'config:shortcut_set_list',
+  ],
+)]
 class Shortcut extends ContentEntityBase implements ShortcutInterface {
 
   /**
diff --git a/core/modules/shortcut/src/Entity/ShortcutSet.php b/core/modules/shortcut/src/Entity/ShortcutSet.php
index 33c28b3bbb4a255c0c96cd328b71364129e0dd12..20bcecb73bea0cfd17afc1b88507cdb7df60439f 100644
--- a/core/modules/shortcut/src/Entity/ShortcutSet.php
+++ b/core/modules/shortcut/src/Entity/ShortcutSet.php
@@ -2,53 +2,59 @@
 
 namespace Drupal\shortcut\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\shortcut\Form\SetCustomize;
+use Drupal\shortcut\Form\ShortcutSetDeleteForm;
+use Drupal\shortcut\ShortcutSetAccessControlHandler;
+use Drupal\shortcut\ShortcutSetForm;
 use Drupal\shortcut\ShortcutSetInterface;
+use Drupal\shortcut\ShortcutSetListBuilder;
+use Drupal\shortcut\ShortcutSetStorage;
 
 /**
  * Defines the Shortcut set configuration entity.
- *
- * @ConfigEntityType(
- *   id = "shortcut_set",
- *   label = @Translation("Shortcut set"),
- *   label_collection = @Translation("Shortcut sets"),
- *   label_singular = @Translation("shortcut set"),
- *   label_plural = @Translation("shortcut sets"),
- *   label_count = @PluralTranslation(
- *     singular = "@count shortcut set",
- *     plural = "@count shortcut sets",
- *   ),
- *   handlers = {
- *     "storage" = "Drupal\shortcut\ShortcutSetStorage",
- *     "access" = "Drupal\shortcut\ShortcutSetAccessControlHandler",
- *     "list_builder" = "Drupal\shortcut\ShortcutSetListBuilder",
- *     "form" = {
- *       "default" = "Drupal\shortcut\ShortcutSetForm",
- *       "add" = "Drupal\shortcut\ShortcutSetForm",
- *       "edit" = "Drupal\shortcut\ShortcutSetForm",
- *       "customize" = "Drupal\shortcut\Form\SetCustomize",
- *       "delete" = "Drupal\shortcut\Form\ShortcutSetDeleteForm"
- *     }
- *   },
- *   config_prefix = "set",
- *   bundle_of = "shortcut",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   links = {
- *     "customize-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}/customize",
- *     "delete-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}/delete",
- *     "edit-form" = "/admin/config/user-interface/shortcut/manage/{shortcut_set}",
- *     "collection" = "/admin/config/user-interface/shortcut",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'shortcut_set',
+  label: new TranslatableMarkup('Shortcut set'),
+  label_collection: new TranslatableMarkup('Shortcut sets'),
+  label_singular: new TranslatableMarkup('shortcut set'),
+  label_plural: new TranslatableMarkup('shortcut sets'),
+  config_prefix: 'set',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ], handlers: [
+    'storage' => ShortcutSetStorage::class,
+    'access' => ShortcutSetAccessControlHandler::class,
+    'list_builder' => ShortcutSetListBuilder::class,
+    'form' => [
+      'default' => ShortcutSetForm::class,
+      'add' => ShortcutSetForm::class,
+      'edit' => ShortcutSetForm::class,
+      'customize' => SetCustomize::class,
+      'delete' => ShortcutSetDeleteForm::class,
+    ],
+  ],
+  links: [
+    'customize-form' => '/admin/config/user-interface/shortcut/manage/{shortcut_set}/customize',
+    'delete-form' => '/admin/config/user-interface/shortcut/manage/{shortcut_set}/delete',
+    'edit-form' => '/admin/config/user-interface/shortcut/manage/{shortcut_set}',
+    'collection' => '/admin/config/user-interface/shortcut',
+  ],
+  bundle_of: 'shortcut',
+  label_count: [
+    'singular' => '@count shortcut set',
+    'plural' => '@count shortcut sets',
+  ],
+  config_export: [
+    'id',
+    'label',
+  ],
+)]
 class ShortcutSet extends ConfigEntityBundleBase implements ShortcutSetInterface {
 
   /**
diff --git a/core/modules/system/src/Entity/Action.php b/core/modules/system/src/Entity/Action.php
index d683bdbc443752590c3b3256bad04dc0f4a03d87..46cebac0ffaf04982f84c522c23cd5295594fe82 100644
--- a/core/modules/system/src/Entity/Action.php
+++ b/core/modules/system/src/Entity/Action.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\system\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Component\Plugin\ConfigurableInterface;
 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
 use Drupal\Component\Plugin\PluginManagerInterface;
@@ -13,31 +15,30 @@
 
 /**
  * Defines the configured action entity.
- *
- * @ConfigEntityType(
- *   id = "action",
- *   label = @Translation("Action"),
- *   label_collection = @Translation("Actions"),
- *   label_singular = @Translation("action"),
- *   label_plural = @Translation("actions"),
- *   label_count = @PluralTranslation(
- *     singular = "@count action",
- *     plural = "@count actions",
- *   ),
- *   admin_permission = "administer actions",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "type",
- *     "plugin",
- *     "configuration",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'action',
+  label: new TranslatableMarkup('Action'),
+  label_collection: new TranslatableMarkup('Actions'),
+  label_singular: new TranslatableMarkup('action'),
+  label_plural: new TranslatableMarkup('actions'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  admin_permission: 'administer actions',
+  label_count: [
+    'singular' => '@count action',
+    'plural' => '@count actions',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'type',
+    'plugin',
+    'configuration',
+  ],
+)]
 class Action extends ConfigEntityBase implements ActionConfigEntityInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/system/src/Entity/Menu.php b/core/modules/system/src/Entity/Menu.php
index 546aa34a86e93032ed1945a66c5a8b37a7f3764f..9beb4d29694b56fd191d7087acf0962e63cdcecd 100644
--- a/core/modules/system/src/Entity/Menu.php
+++ b/core/modules/system/src/Entity/Menu.php
@@ -2,40 +2,43 @@
 
 namespace Drupal\system\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\system\MenuAccessControlHandler;
 use Drupal\system\MenuInterface;
+use Drupal\system\MenuStorage;
 
 /**
  * Defines the Menu configuration entity class.
- *
- * @ConfigEntityType(
- *   id = "menu",
- *   label = @Translation("Menu"),
- *   label_collection = @Translation("Menus"),
- *   label_singular = @Translation("menu"),
- *   label_plural = @Translation("menus"),
- *   label_count = @PluralTranslation(
- *     singular = "@count menu",
- *     plural = "@count menus",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\system\MenuAccessControlHandler",
- *     "storage" = "Drupal\system\MenuStorage",
- *   },
- *   admin_permission = "administer menu",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "description",
- *     "locked",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'menu',
+  label: new TranslatableMarkup('Menu'),
+  label_collection: new TranslatableMarkup('Menus'),
+  label_singular: new TranslatableMarkup('menu'),
+  label_plural: new TranslatableMarkup('menus'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'access' => MenuAccessControlHandler::class,
+    'storage' => MenuStorage::class,
+  ],
+  admin_permission: 'administer menu',
+  label_count: [
+    'singular' => '@count menu',
+    'plural' => '@count menus',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'description',
+    'locked',
+  ],
+)]
 class Menu extends ConfigEntityBase implements MenuInterface {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntitySerializedField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntitySerializedField.php
index 032cdca806c1c1a32449aaf35bc4b9b254ca49af..d4f33a497f63be817332724eae31e2d37534b33b 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntitySerializedField.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntitySerializedField.php
@@ -4,30 +4,31 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 
 /**
  * Defines a test class for testing fields with a serialized column.
- *
- * @ContentEntityType(
- *   id = "entity_test_serialized_field",
- *   label = @Translation("Test serialized fields"),
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name"
- *   },
- *   base_table = "entity_test_serialized_fields",
- *   persistent_cache = FALSE,
- *   serialized_field_property_names = {
- *     "serialized_long" = {
- *       "value"
- *     }
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_serialized_field',
+  label: new TranslatableMarkup('Test serialized fields'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  base_table: 'entity_test_serialized_fields',
+  additional: [
+    'serialized_field_property_names' => [
+      'serialized_long' => ['value'],
+    ],
+  ],
+)]
 class EntitySerializedField extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
index dfd5ea398e9d10aa9decfeeeed7cd960b397e7f7..2afedb543ef3cc45aec7c58a8be61b83b03e39c6 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTest.php
@@ -4,55 +4,60 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestListBuilder;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\entity_test\EntityTestViewsData;
 use Drupal\user\EntityOwnerInterface;
 use Drupal\user\UserInterface;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test",
- *   label = @Translation("Test entity"),
- *   handlers = {
- *     "list_builder" = "Drupal\entity_test\EntityTestListBuilder",
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *     "views_data" = "Drupal\entity_test\EntityTestViewsData"
- *   },
- *   base_table = "entity_test",
- *   admin_permission = "administer entity_test content",
- *   persistent_cache = FALSE,
- *   list_cache_contexts = { "entity_test_view_grants" },
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "canonical" = "/entity_test/{entity_test}",
- *     "add-form" = "/entity_test/add",
- *     "edit-form" = "/entity_test/manage/{entity_test}/edit",
- *     "delete-form" = "/entity_test/delete/entity_test/{entity_test}",
- *   },
- *   field_ui_base_route = "entity.entity_test.admin_form",
- * )
- *
- * Note that this entity type annotation intentionally omits the "create" link
- * template. See https://www.drupal.org/node/2293697.
  */
+#[ContentEntityType(
+  id: 'entity_test',
+  label: new TranslatableMarkup('Test entity'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'list_builder' => EntityTestListBuilder::class,
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'route_provider' => ['html' => DefaultHtmlRouteProvider::class],
+    'views_data' => EntityTestViewsData::class,
+  ],
+  links: [
+    'canonical' => '/entity_test/{entity_test}',
+    'add-form' => '/entity_test/add',
+    'edit-form' => '/entity_test/manage/{entity_test}/edit',
+    'delete-form' => '/entity_test/delete/entity_test/{entity_test}',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test',
+  field_ui_base_route: 'entity.entity_test.admin_form',
+  list_cache_contexts: [
+    'entity_test_view_grants',
+  ],
+)]
 class EntityTest extends ContentEntityBase implements EntityOwnerInterface {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAddPage.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAddPage.php
index c4ae5473aa480e9879243cf01ead7699e9550dfc..da2226e32e778fcc52a6033dfa0544614e5e71ac 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAddPage.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAddPage.php
@@ -4,34 +4,38 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestForm;
+
 /**
  * Test entity class routes.
- *
- * @ContentEntityType(
- *   id = "entity_test_add_page",
- *   label = @Translation("Entity test route add page"),
- *   handlers = {
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   admin_permission = "administer entity_test content",
- *   base_table = "entity_test_add_page",
- *   render_cache = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *   },
- *   links = {
- *     "add-page" = "/entity_test_add_page/{user}/add",
- *     "add-form" = "/entity_test_add_page/add/{user}/form",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_add_page',
+  label: new TranslatableMarkup('Entity test route add page'),
+  render_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  handlers: [
+    'form' => [
+      'default' => EntityTestForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-page' => '/entity_test_add_page/{user}/add',
+    'add-form' => '/entity_test_add_page/add/{user}/form',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_add_page',
+)]
 class EntityTestAddPage extends EntityTest {
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php
index 8977ba4338299f425fae9ee182d5621719e9f2f7..70dc4327870cfa7a428d1e58eef4821b83e11aae 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestAdminRoutes.php
@@ -4,42 +4,48 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
+
 /**
  * Defines a test entity type with administrative routes.
- *
- * @ContentEntityType(
- *   id = "entity_test_admin_routes",
- *   label = @Translation("Test entity - admin routes"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_admin_routes",
- *   data_table = "entity_test_admin_routes_property_data",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "canonical" = "/entity_test_admin_routes/manage/{entity_test_admin_routes}",
- *     "edit-form" = "/entity_test_admin_routes/manage/{entity_test_admin_routes}/edit",
- *     "delete-form" = "/entity_test/delete/entity_test_admin_routes/{entity_test_admin_routes}",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_admin_routes',
+  label: new TranslatableMarkup('Test entity - admin routes'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => ['html' => AdminHtmlRouteProvider::class],
+  ],
+  links: [
+    'canonical' => '/entity_test_admin_routes/manage/{entity_test_admin_routes}',
+    'edit-form' => '/entity_test_admin_routes/manage/{entity_test_admin_routes}/edit',
+    'delete-form' => '/entity_test/delete/entity_test_admin_routes/{entity_test_admin_routes}',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_admin_routes',
+  data_table: 'entity_test_admin_routes_property_data',
+  translatable: TRUE,
+)]
 class EntityTestAdminRoutes extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php
index afdae49f4507827110574716ca7027c020039f40..2474ceecab57f8a92b214f26af08c8462a22af32 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBaseFieldDisplay.php
@@ -4,43 +4,43 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestForm;
 use Drupal\entity_test\FieldStorageDefinition;
 
 /**
  * Defines a test entity class for base fields display.
- *
- * @ContentEntityType(
- *   id = "entity_test_base_field_display",
- *   label = @Translation("Test entity - base field display"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_base_field_display",
- *   admin_permission = "administer entity_test content",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "name",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "canonical" = "/entity_test_base_field_display/{entity_test_base_field_display}/edit",
- *     "add-form" = "/entity_test_base_field_display/add",
- *     "edit-form" = "/entity_test_base_field_display/manage/{entity_test_base_field_display}",
- *     "delete-form" = "/entity_test/delete/entity_test_base_field_display/{entity_test_base_field_display}/edit",
- *   },
- *   field_ui_base_route = "entity.entity_test_base_field_display.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_base_field_display',
+  label: new TranslatableMarkup('Test entity - base field display'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'name',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => ['default' => EntityTestForm::class],
+    'route_provider' => ['html' => DefaultHtmlRouteProvider::class],
+  ],
+  links: [
+    'canonical' => '/entity_test_base_field_display/{entity_test_base_field_display}/edit',
+    'add-form' => '/entity_test_base_field_display/add',
+    'edit-form' => '/entity_test_base_field_display/manage/{entity_test_base_field_display}',
+    'delete-form' => '/entity_test/delete/entity_test_base_field_display/{entity_test_base_field_display}/edit',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_base_field_display',
+  field_ui_base_route: 'entity.entity_test_base_field_display.admin_form',
+)]
 class EntityTestBaseFieldDisplay extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php
index 7e039ac32430b739ac8aca47d05f8181e9ea6047..053d3fcb9cb4c64b32ab044b80ca23da110884e6 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestBundle.php
@@ -4,41 +4,45 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\BundleEntityFormBase;
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\Core\Entity\EntityDescriptionInterface;
 
 /**
  * Defines the Test entity bundle configuration entity.
- *
- * @ConfigEntityType(
- *   id = "entity_test_bundle",
- *   label = @Translation("Test entity bundle"),
- *   handlers = {
- *     "access" = "\Drupal\Core\Entity\EntityAccessControlHandler",
- *     "form" = {
- *       "default" = "\Drupal\Core\Entity\BundleEntityFormBase",
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   admin_permission = "administer entity_test_bundle content",
- *   config_prefix = "entity_test_bundle",
- *   bundle_of = "entity_test_with_bundle",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "description",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_bundle/add",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'entity_test_bundle',
+  label: new TranslatableMarkup('Test entity bundle'),
+  config_prefix: 'entity_test_bundle',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'access' => EntityAccessControlHandler::class,
+    'form' => [
+      'default' => BundleEntityFormBase::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_bundle/add',
+  ],
+  admin_permission: 'administer entity_test_bundle content',
+  bundle_of: 'entity_test_with_bundle',
+  config_export: [
+    'id',
+    'label',
+    'description',
+  ],
+)]
 class EntityTestBundle extends ConfigEntityBundleBase implements EntityDescriptionInterface {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php
index a59d264194a6ea661195c3c08c236a14890f6822..bd3367d6df397708e76a54822f2a05b4c970f627 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCache.php
@@ -4,26 +4,30 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestForm;
+
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_cache",
- *   label = @Translation("Test entity with field cache"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
- *     },
- *   },
- *   base_table = "entity_test_cache",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type"
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_cache',
+  label: new TranslatableMarkup('Test entity with field cache'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+    ],
+  ],
+  base_table: 'entity_test_cache',
+)]
 class EntityTestCache extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php
index dc34902c87785d61a3821c7428e559f80bd11214..be31e8066604c0f8d5566c20e8e55c2707b35fc3 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestCompositeConstraint.php
@@ -4,33 +4,35 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\entity_test\EntityTestForm;
 
 /**
  * Defines a test class for testing composite constraints.
- *
- * @ContentEntityType(
- *   id = "entity_test_composite_constraint",
- *   label = @Translation("Test entity constraints with composite constraint"),
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name"
- *   },
- *   handlers = {
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
- *     }
- *   },
- *   base_table = "entity_test_composite_constraint",
- *   persistent_cache = FALSE,
- *   constraints = {
- *     "EntityTestComposite" = {},
- *     "EntityTestEntityLevel" = {},
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_composite_constraint',
+  label: new TranslatableMarkup('Test entity constraints with composite constraint'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  handlers: [
+    'form' => [
+      'default' => EntityTestForm::class,
+    ],
+  ],
+  base_table: 'entity_test_composite_constraint',
+  constraints: [
+    'EntityTestComposite' => [],
+    'EntityTestEntityLevel' => [],
+  ],
+)]
 class EntityTestCompositeConstraint extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php
index fa0674298c43f55ee608fce01a9e3cbbd4912745..14ed8bc2b9f810cdf8bf1615144e7252081f9d62 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedBundleField.php
@@ -4,10 +4,12 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Field\FieldDefinition;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestViewsData;
 use Drupal\entity_test\FieldStorageDefinition;
 use Drupal\entity_test\Plugin\Field\ComputedReferenceTestFieldItemList;
 use Drupal\entity_test\Plugin\Field\ComputedTestBundleFieldItemList;
@@ -16,23 +18,22 @@
 
 /**
  * An entity used for testing computed bundle field values.
- *
- * @ContentEntityType(
- *   id = "entity_test_comp_bund_fld",
- *   label = @Translation("Entity Test computed bundle field"),
- *   base_table = "entity_test_comp_bund_fld",
- *   handlers = {
- *     "views_data" = "Drupal\entity_test\EntityTestViewsData"
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "label" = "name",
- *     "bundle" = "type",
- *   },
- *   admin_permission = "administer entity_test content",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_comp_bund_fld',
+  label: new TranslatableMarkup('Entity Test computed bundle field'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'label' => 'name',
+    'bundle' => 'type',
+  ],
+  handlers: [
+    'views_data' => EntityTestViewsData::class,
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_comp_bund_fld',
+)]
 class EntityTestComputedBundleField extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php
index 93785bfa8b8f241490c68efaad72d71dd9a647e8..83d925a9028d0f454b52afb5e041e3434d0de458 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestComputedField.php
@@ -4,9 +4,11 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestViewsData;
 use Drupal\entity_test\Plugin\Field\ComputedReferenceTestFieldItemList;
 use Drupal\entity_test\Plugin\Field\ComputedTestCacheableIntegerItemList;
 use Drupal\entity_test\Plugin\Field\ComputedTestCacheableStringItemList;
@@ -14,25 +16,24 @@
 
 /**
  * An entity used for testing computed field values.
- *
- * @ContentEntityType(
- *   id = "entity_test_computed_field",
- *   label = @Translation("Entity Test computed field"),
- *   base_table = "entity_test_computed_field",
- *   handlers = {
- *     "views_data" = "Drupal\entity_test\EntityTestViewsData"
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "label" = "name",
- *   },
- *   admin_permission = "administer entity_test content",
- *   links = {
- *     "canonical" = "/entity_test_computed_field/{entity_test_computed_field}",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_computed_field',
+  label: new TranslatableMarkup('Entity Test computed field'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'label' => 'name',
+  ],
+  handlers: [
+    'views_data' => EntityTestViewsData::class,
+  ],
+  links: [
+    'canonical' => '/entity_test_computed_field/{entity_test_computed_field}',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_computed_field',
+)]
 class EntityTestComputedField extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php
index 7e2f4f48969708b293d4240fa9c5a34fdc4a0fa0..6d21eb2278fdab5032ecb2b9fb688c1fb89711f0 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraintViolation.php
@@ -4,30 +4,32 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestForm;
 
 /**
  * Defines the test entity class for testing entity constraint violations.
- *
- * @ContentEntityType(
- *   id = "entity_test_constraint_violation",
- *   label = @Translation("Test entity constraint violation"),
- *   handlers = {
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
- *     }
- *   },
- *   base_table = "entity_test_constraint_violation",
- *   persistent_cache = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name"
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_constraint_violation',
+  label: new TranslatableMarkup('Test entity constraint violation'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  handlers: [
+    'form' => [
+      'default' => EntityTestForm::class,
+    ],
+  ],
+  base_table: 'entity_test_constraint_violation',
+)]
 class EntityTestConstraintViolation extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php
index 0cfdd24fcb0b389119c083d5fc004ae2ed392d9f..ab8214fa444843b81ddbd4146547aa2644d59409 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestConstraints.php
@@ -4,6 +4,8 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\EntityChangedInterface;
@@ -11,23 +13,22 @@
 
 /**
  * Defines a test class for testing the definition of entity level constraints.
- *
- * @ContentEntityType(
- *   id = "entity_test_constraints",
- *   label = @Translation("Test entity constraints"),
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name"
- *   },
- *   base_table = "entity_test_constraints",
- *   persistent_cache = FALSE,
- *   constraints = {
- *     "NotNull" = {}
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_constraints',
+  label: new TranslatableMarkup('Test entity constraints'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  base_table: 'entity_test_constraints',
+  constraints: [
+    'NotNull' => [],
+  ],
+)]
 class EntityTestConstraints extends EntityTest implements EntityChangedInterface {
 
   use EntityChangedTrait;
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php
index bcb8a34fbc732afad78ce3d0afdf621898196c91..a977e8cb1a3457f6aa4c80dc68198ff292320e2f 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultAccess.php
@@ -4,19 +4,21 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Defines a test entity class with no access control handler.
- *
- * @ContentEntityType(
- *   id = "entity_test_default_access",
- *   label = @Translation("Test entity with default access"),
- *   base_table = "entity_test_default_access",
- *   entity_keys = {
- *     "id" = "id",
- *     "bundle" = "type"
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_default_access',
+  label: new TranslatableMarkup('Test entity with default access'),
+  entity_keys: [
+    'id' => 'id',
+    'bundle' => 'type',
+  ],
+  base_table: 'entity_test_default_access',
+)]
 class EntityTestDefaultAccess extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php
index ed5d214c04a49da18e17a05e58f2266d8556afbd..3d5aaca9080cad20031acc29ed98f33fc6cef0a4 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestDefaultValue.php
@@ -4,24 +4,25 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 
 /**
  * Defines a test entity class for testing default values.
- *
- * @ContentEntityType(
- *   id = "entity_test_default_value",
- *   label = @Translation("Test entity for default values"),
- *   base_table = "entity_test_default_value",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "langcode" = "langcode"
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_default_value',
+  label: new TranslatableMarkup('Test entity for default values'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'langcode' => 'langcode',
+  ],
+  base_table: 'entity_test_default_value',
+)]
 class EntityTestDefaultValue extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php
index 45879565529c407ca79d0c9ddc3e7fda058f1fa1..247e659e54c8fb2e4fddcdeb3a5e714c4141bb83 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestExternal.php
@@ -4,25 +4,26 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
 
 /**
  * Test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_external",
- *   label = @Translation("Entity test external"),
- *   base_table = "entity_test_external",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *   },
- *   links = {
- *     "canonical" = "/entity_test_external/{entity_test_external}"
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_external',
+  label: new TranslatableMarkup('Entity test external'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+  ],
+  links: [
+    'canonical' => '/entity_test_external/{entity_test_external}',
+  ],
+  base_table: 'entity_test_external',
+)]
 class EntityTestExternal extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php
index 9c06a5842892edd486f0b39bcb74355070cf29f1..7d3e145243ab7b01e4a45382fa9469cf5ee95907 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldMethods.php
@@ -4,40 +4,47 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_field_methods",
- *   label = @Translation("Test entity - field methods and data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_field_methods",
- *   data_table = "entity_test_field_methods_property",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_field_methods',
+  label: new TranslatableMarkup('Test entity - field methods and data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_field_methods',
+  data_table: 'entity_test_field_methods_property',
+  translatable: TRUE,
+)]
 class EntityTestFieldMethods extends EntityTestMul {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php
index 98e3f7ee19ea26d3c100f0ceefbfda507560f7a6..87e9a48e611ec59dc3a44dbb439d54ec438f95ca 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestFieldOverride.php
@@ -4,22 +4,23 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 
 /**
  * Defines a test entity class for testing default values.
- *
- * @ContentEntityType(
- *   id = "entity_test_field_override",
- *   label = @Translation("Test entity field overrides"),
- *   base_table = "entity_test_field_override",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type"
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_field_override',
+  label: new TranslatableMarkup('Test entity field overrides'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+  ],
+  base_table: 'entity_test_field_override',
+)]
 class EntityTestFieldOverride extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php
index eb8ed9bcac312d05b7d39f8ebe3f1a004592a37a..f86fa46067c8f3cbecfc45b181fbb9a917f9aada 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestLabel.php
@@ -4,27 +4,31 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+
 /**
  * Test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_label",
- *   label = @Translation("Entity Test label"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder"
- *   },
- *   base_table = "entity_test_label",
- *   render_cache = FALSE,
- *   entity_keys = {
- *     "uuid" = "uuid",
- *     "id" = "id",
- *     "label" = "name",
- *     "bundle" = "type",
- *     "langcode" = "langcode",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_label',
+  label: new TranslatableMarkup('Entity Test label'),
+  render_cache: FALSE,
+  entity_keys: [
+    'uuid' => 'uuid',
+    'id' => 'id',
+    'label' => 'name',
+    'bundle' => 'type',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'view_builder' => TestViewBuilder::class,
+  ],
+  base_table: 'entity_test_label',
+)]
 class EntityTestLabel extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php
index ed995b210d4fdefb1debb562873161ac5c1bd6b2..fd9698ade4cad70574d0dce0f8d2216e81eb61fd 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMapField.php
@@ -4,25 +4,26 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 
 /**
  * An entity used for testing map base field values.
- *
- * @ContentEntityType(
- *   id = "entity_test_map_field",
- *   label = @Translation("Entity Test map field"),
- *   base_table = "entity_test_map_field",
- *   entity_keys = {
- *     "uuid" = "uuid",
- *     "id" = "id",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   admin_permission = "administer entity_test content",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_map_field',
+  label: new TranslatableMarkup('Entity Test map field'),
+  entity_keys: [
+    'uuid' => 'uuid',
+    'id' => 'id',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_map_field',
+)]
 class EntityTestMapField extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php
index 03a070e09672aeb939c0176585598f5359b165ad..8eb4e89808cd7aaa8d428685ccb9eb0bdce27820 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMul.php
@@ -4,47 +4,52 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul",
- *   label = @Translation("Test entity - data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_mul",
- *   data_table = "entity_test_mul_property_data",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "add-page" = "/entity_test_mul/add",
- *     "add-form" = "/entity_test_mul/add/{type}",
- *     "canonical" = "/entity_test_mul/manage/{entity_test_mul}",
- *     "edit-form" = "/entity_test_mul/manage/{entity_test_mul}/edit",
- *     "delete-form" = "/entity_test/delete/entity_test_mul/{entity_test_mul}",
- *   },
- *   field_ui_base_route = "entity.entity_test_mul.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul',
+  label: new TranslatableMarkup('Test entity - data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => ['html' => DefaultHtmlRouteProvider::class],
+  ],
+  links: [
+    'add-page' => '/entity_test_mul/add',
+    'add-form' => '/entity_test_mul/add/{type}',
+    'canonical' => '/entity_test_mul/manage/{entity_test_mul}',
+    'edit-form' => '/entity_test_mul/manage/{entity_test_mul}/edit',
+    'delete-form' => '/entity_test/delete/entity_test_mul/{entity_test_mul}',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_mul',
+  data_table: 'entity_test_mul_property_data',
+  translatable: TRUE,
+  field_ui_base_route: 'entity.entity_test_mul.admin_form',
+)]
 class EntityTestMul extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulBundle.php
index 3ed9577a1d7634317e038ab215fd9c562b88ad18..8debeb0aa3efeb52ea06f4ef5e2137298bb7e81f 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulBundle.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulBundle.php
@@ -4,40 +4,44 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\BundleEntityFormBase;
+use Drupal\Core\Entity\EntityAccessControlHandler;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\Core\Entity\EntityDescriptionInterface;
 
 /**
  * Defines the Test entity mul bundle configuration entity.
- *
- * @ConfigEntityType(
- *   id = "entity_test_mul_bundle",
- *   label = @Translation("Test entity multilingual bundle"),
- *   handlers = {
- *     "access" = "\Drupal\Core\Entity\EntityAccessControlHandler",
- *     "form" = {
- *       "default" = "\Drupal\Core\Entity\BundleEntityFormBase",
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   admin_permission = "administer entity_test_mul_with_bundle content",
- *   bundle_of = "entity_test_mul_with_bundle",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "description",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mul_bundle/add",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'entity_test_mul_bundle',
+  label: new TranslatableMarkup('Test entity multilingual bundle'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+  ],
+  handlers: [
+    'access' => EntityAccessControlHandler::class,
+    'form' => [
+      'default' => BundleEntityFormBase::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_mul_bundle/add',
+  ],
+  admin_permission: 'administer entity_test_mul_with_bundle content',
+  bundle_of: 'entity_test_mul_with_bundle',
+  config_export: [
+    'id',
+    'label',
+    'description',
+  ],
+)]
 class EntityTestMulBundle extends ConfigEntityBundleBase implements EntityDescriptionInterface {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php
index 9b497762df5acc047a881b6ccc6e79701de12720..bfb0f6b10adeae21b9168807804b762b1274ee94 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulChanged.php
@@ -4,48 +4,55 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityChangedInterface;
 use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul_changed",
- *   label = @Translation("Test entity - multiple changed and data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData"
- *   },
- *   base_table = "entity_test_mul_changed",
- *   data_table = "entity_test_mul_changed_property",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode"
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mul_changed/add",
- *     "canonical" = "/entity_test_mul_changed/manage/{entity_test_mul_changed}",
- *     "edit-form" = "/entity_test_mul_changed/manage/{entity_test_mul_changed}/edit",
- *     "delete-form" = "/entity_test/delete/entity_test_mul_changed/{entity_test_mul_changed}",
- *   },
- *   field_ui_base_route = "entity.entity_test_mul_changed.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul_changed',
+  label: new TranslatableMarkup('Test entity - multiple changed and data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+    'views_data' => EntityViewsData::class,
+  ],
+  links: [
+    'add-form' => '/entity_test_mul_changed/add',
+    'canonical' => '/entity_test_mul_changed/manage/{entity_test_mul_changed}',
+    'edit-form' => '/entity_test_mul_changed/manage/{entity_test_mul_changed}/edit',
+    'delete-form' => '/entity_test/delete/entity_test_mul_changed/{entity_test_mul_changed}',
+  ],
+  base_table: 'entity_test_mul_changed',
+  data_table: 'entity_test_mul_changed_property',
+  translatable: TRUE,
+  field_ui_base_route: 'entity.entity_test_mul_changed.admin_form',
+)]
 class EntityTestMulChanged extends EntityTestMul implements EntityChangedInterface {
 
   use EntityChangedTrait;
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php
index f19500719bf10afcc201f77a426b1ec8eeea408c..828032e8682c41655fe7dd2efd9500cf0627c5de 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulDefaultValue.php
@@ -4,42 +4,48 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul_default_value",
- *   label = @Translation("Test entity - multiple default value and data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData"
- *   },
- *   base_table = "entity_test_mul_default_value",
- *   data_table = "entity_test_mul_default_value_property_data",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode"
- *   },
- *   links = {
- *     "canonical" = "/entity_test_mul_default_value/manage/{entity_test_mul_default_value}",
- *     "edit-form" = "/entity_test_mul_default_value/manage/{entity_test_mul_default_value}",
- *     "delete-form" = "/entity_test/delete/entity_test_mul_default_value/{entity_test_mul_default_value}",
- *   },
- *   field_ui_base_route = "entity.entity_test_mul.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul_default_value',
+  label: new TranslatableMarkup('Test entity - multiple default value and data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+  ],
+  links: [
+    'canonical' => '/entity_test_mul_default_value/manage/{entity_test_mul_default_value}',
+    'edit-form' => '/entity_test_mul_default_value/manage/{entity_test_mul_default_value}',
+    'delete-form' => '/entity_test/delete/entity_test_mul_default_value/{entity_test_mul_default_value}',
+  ],
+  base_table: 'entity_test_mul_default_value',
+  data_table: 'entity_test_mul_default_value_property_data',
+  translatable: TRUE,
+  field_ui_base_route: 'entity.entity_test_mul.admin_form',
+)]
 class EntityTestMulDefaultValue extends EntityTestMul {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php
index 2316c6db9f8bdf1995916ecc2f632fd92e3157e7..a536f72bcd4f8f1acf9d5cf53f22a0549bb11a10 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulLangcodeKey.php
@@ -4,45 +4,52 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
+
 /**
  * Defines a test entity class using a custom langcode entity key.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul_langcode_key",
- *   label = @Translation("Test entity - data table - langcode key"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_mul_langcode_key",
- *   data_table = "entity_test_mul_langcode_key_field_data",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "custom_langcode_key",
- *     "default_langcode" = "custom_default_langcode_key",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mul_langcode_key/add",
- *     "canonical" = "/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}",
- *     "edit-form" = "/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}/edit",
- *     "delete-form" = "/entity_test/delete/entity_test_mul_langcode_key/{entity_test_mul_langcode_key}",
- *   },
- *   field_ui_base_route = "entity.entity_test_mul_langcode_key.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul_langcode_key',
+  label: new TranslatableMarkup('Test entity - data table - langcode key'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'custom_langcode_key',
+    'default_langcode' => 'custom_default_langcode_key',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_mul_langcode_key/add',
+    'canonical' => '/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}',
+    'edit-form' => '/entity_test_mul_langcode_key/manage/{entity_test_mul_langcode_key}/edit',
+    'delete-form' => '/entity_test/delete/entity_test_mul_langcode_key/{entity_test_mul_langcode_key}',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_mul_langcode_key',
+  data_table: 'entity_test_mul_langcode_key_field_data', translatable: TRUE,
+  field_ui_base_route: 'entity.entity_test_mul_langcode_key.admin_form',
+)]
 class EntityTestMulLangcodeKey extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
index b147853fcd19af373c1532f5b80878e571e5fd3f..58e0072e0fd7ef500dd8aac90b07644df5282bfc 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRev.php
@@ -4,51 +4,56 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mulrev",
- *   label = @Translation("Test entity - mul revisions and data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_mulrev",
- *   data_table = "entity_test_mulrev_property_data",
- *   revision_table = "entity_test_mulrev_revision",
- *   revision_data_table = "entity_test_mulrev_property_revision",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   show_revision_ui = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "revision" = "revision_id",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mulrev/add",
- *     "canonical" = "/entity_test_mulrev/manage/{entity_test_mulrev}",
- *     "delete-form" = "/entity_test/delete/entity_test_mulrev/{entity_test_mulrev}",
- *     "edit-form" = "/entity_test_mulrev/manage/{entity_test_mulrev}/edit",
- *     "revision" = "/entity_test_mulrev/{entity_test_mulrev}/revision/{entity_test_mulrev_revision}/view",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mulrev',
+  label: new TranslatableMarkup('Test entity - mul revisions and data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'revision' => 'revision_id',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => ['html' => DefaultHtmlRouteProvider::class],
+  ],
+  links: [
+    'add-form' => '/entity_test_mulrev/add',
+    'canonical' => '/entity_test_mulrev/manage/{entity_test_mulrev}',
+    'delete-form' => '/entity_test/delete/entity_test_mulrev/{entity_test_mulrev}',
+    'edit-form' => '/entity_test_mulrev/manage/{entity_test_mulrev}/edit',
+    'revision' => '/entity_test_mulrev/{entity_test_mulrev}/revision/{entity_test_mulrev_revision}/view',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_mulrev',
+  data_table: 'entity_test_mulrev_property_data',
+  revision_table: 'entity_test_mulrev_revision',
+  revision_data_table: 'entity_test_mulrev_property_revision',
+  translatable: TRUE,
+  show_revision_ui: TRUE,
+)]
 class EntityTestMulRev extends EntityTestRev {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php
index f965884a6dd9db5686f2221bde2945d14465d38a..e88e6714e637f16b5816581068ba7c8c130a2329 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChanged.php
@@ -4,49 +4,56 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mulrev_changed",
- *   label = @Translation("Test entity - mul changed revisions and data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData"
- *   },
- *   base_table = "entity_test_mulrev_changed",
- *   data_table = "entity_test_mulrev_changed_property",
- *   revision_table = "entity_test_mulrev_changed_revision",
- *   revision_data_table = "entity_test_mulrev_changed_property_revision",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "revision" = "revision_id",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mulrev_changed/add",
- *     "canonical" = "/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}",
- *     "delete-form" = "/entity_test/delete/entity_test_mulrev_changed/{entity_test_mulrev_changed}",
- *     "edit-form" = "/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}/edit",
- *     "revision" = "/entity_test_mulrev_changed/{entity_test_mulrev_changed}/revision/{entity_test_mulrev_changed_revision}/view",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mulrev_changed',
+  label: new TranslatableMarkup('Test entity - mul changed revisions and data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'revision' => 'revision_id',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+    'views_data' => EntityViewsData::class,
+  ],
+  links: [
+    'add-form' => '/entity_test_mulrev_changed/add',
+    'canonical' => '/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}',
+    'delete-form' => '/entity_test/delete/entity_test_mulrev_changed/{entity_test_mulrev_changed}',
+    'edit-form' => '/entity_test_mulrev_changed/manage/{entity_test_mulrev_changed}/edit',
+    'revision' => '/entity_test_mulrev_changed/{entity_test_mulrev_changed}/revision/{entity_test_mulrev_changed_revision}/view',
+  ],
+  base_table: 'entity_test_mulrev_changed',
+  data_table: 'entity_test_mulrev_changed_property',
+  revision_table: 'entity_test_mulrev_changed_revision',
+  revision_data_table: 'entity_test_mulrev_changed_property_revision',
+  translatable: TRUE,
+)]
 class EntityTestMulRevChanged extends EntityTestMulChanged {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php
index 8b97ae48235bf8485b20e30c9f4975b04651a751..4b0eb399546753afd115f1c95ccd74259a4c660b 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevChangedWithRevisionLog.php
@@ -4,33 +4,34 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\RevisionLogEntityTrait;
 use Drupal\Core\Entity\RevisionLogInterface;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mulrev_changed_rev",
- *   label = @Translation("Test entity - revisions log and data table"),
- *   base_table = "entity_test_mulrev_changed_revlog",
- *   revision_table = "entity_test_mulrev_changed_revlog_revision",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "revision" = "revision_id",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message"
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mulrev_changed_rev',
+  label: new TranslatableMarkup('Test entity - revisions log and data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'revision' => 'revision_id',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  base_table: 'entity_test_mulrev_changed_revlog',
+  revision_table: 'entity_test_mulrev_changed_revlog_revision',
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ],
+)]
 class EntityTestMulRevChangedWithRevisionLog extends EntityTestMulRevChanged implements RevisionLogInterface {
 
   use RevisionLogEntityTrait;
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php
index 68757f50da670e9faf14790f142dd05f642bba16..412c60e9ae9164ecfb8d668fc3ebdc5549e72f23 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulRevPub.php
@@ -4,55 +4,63 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Form\DeleteMultipleForm;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\EntityPublishedTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mulrevpub",
- *   label = @Translation("Test entity - revisions, data table, and published interface"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm",
- *       "delete-multiple-confirm" = "Drupal\Core\Entity\Form\DeleteMultipleForm"
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_mulrevpub",
- *   data_table = "entity_test_mulrevpub_property_data",
- *   revision_table = "entity_test_mulrevpub_revision",
- *   revision_data_table = "entity_test_mulrevpub_property_revision",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   show_revision_ui = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "revision" = "revision_id",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *     "published" = "status",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mulrevpub/add",
- *     "canonical" = "/entity_test_mulrevpub/manage/{entity_test_mulrevpub}",
- *     "delete-form" = "/entity_test/delete/entity_test_mulrevpub/{entity_test_mulrevpub}",
- *     "delete-multiple-form" = "/entity_test/delete",
- *     "edit-form" = "/entity_test_mulrevpub/manage/{entity_test_mulrevpub}/edit",
- *     "revision" = "/entity_test_mulrevpub/{entity_test_mulrevpub}/revision/{entity_test_mulrevpub_revision}/view",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mulrevpub',
+  label: new TranslatableMarkup('Test entity - revisions, data table, and published interface'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'revision' => 'revision_id',
+    'label' => 'name',
+    'langcode' => 'langcode',
+    'published' => 'status',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+      'delete-multiple-confirm' => DeleteMultipleForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_mulrevpub/add',
+    'canonical' => '/entity_test_mulrevpub/manage/{entity_test_mulrevpub}',
+    'delete-form' => '/entity_test/delete/entity_test_mulrevpub/{entity_test_mulrevpub}',
+    'delete-multiple-form' => '/entity_test/delete',
+    'edit-form' => '/entity_test_mulrevpub/manage/{entity_test_mulrevpub}/edit',
+    'revision' => '/entity_test_mulrevpub/{entity_test_mulrevpub}/revision/{entity_test_mulrevpub_revision}/view',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_mulrevpub',
+  data_table: 'entity_test_mulrevpub_property_data',
+  revision_table: 'entity_test_mulrevpub_revision',
+  revision_data_table: 'entity_test_mulrevpub_property_revision',
+  translatable: TRUE,
+  show_revision_ui: TRUE,
+)]
 class EntityTestMulRevPub extends EntityTestMulRev implements EntityPublishedInterface {
 
   use EntityPublishedTrait;
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulWithBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulWithBundle.php
index e72067ce9a30f4169388784a7e9186e907856744..03d0a833fe9f3cb4a73e3e7986ca8a51d62ab6d4 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulWithBundle.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMulWithBundle.php
@@ -4,48 +4,57 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
+
 /**
  * Defines the multilingual test entity class with bundles.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul_with_bundle",
- *   label = @Translation("Test entity multilingual with bundle - data table"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm"
- *     },
- *     "translation" = "Drupal\content_translation\ContentTranslationHandler",
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_mul_with_bundle",
- *   data_table = "entity_test_mul_with_bundle_property_data",
- *   admin_permission = "administer entity_test content",
- *   translatable = TRUE,
- *   permission_granularity = "bundle",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   bundle_entity_type = "entity_test_mul_bundle",
- *   links = {
- *     "add-page" = "/entity_test_mul_with_bundle/add",
- *     "add-form" = "/entity_test_mul_with_bundle/add/{type}",
- *     "canonical" = "/entity_test_mul_with_bundle/manage/{entity_test_mul_with_bundle}",
- *     "edit-form" = "/entity_test_mul_with_bundle/manage/{entity_test_mul_with_bundle}/edit",
- *     "delete-form" = "/entity_test/delete/entity_test_mul_with_bundle/{entity_test_mul_with_bundle}",
- *   },
- *   field_ui_base_route = "entity.entity_test_mul_with_bundle.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul_with_bundle',
+  label: new TranslatableMarkup('Test entity multilingual with bundle - data table'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+    ],
+    'translation' => ContentTranslationHandler::class,
+    'views_data' => EntityViewsData::class,
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-page' => '/entity_test_mul_with_bundle/add',
+    'add-form' => '/entity_test_mul_with_bundle/add/{type}',
+    'canonical' => '/entity_test_mul_with_bundle/manage/{entity_test_mul_with_bundle}',
+    'edit-form' => '/entity_test_mul_with_bundle/manage/{entity_test_mul_with_bundle}/edit',
+    'delete-form' => '/entity_test/delete/entity_test_mul_with_bundle/{entity_test_mul_with_bundle}',
+  ],
+  admin_permission: 'administer entity_test content',
+  permission_granularity: 'bundle',
+  bundle_entity_type: 'entity_test_mul_bundle',
+  base_table: 'entity_test_mul_with_bundle',
+  data_table: 'entity_test_mul_with_bundle_property_data',
+  translatable: TRUE,
+  field_ui_base_route: 'entity.entity_test_mul_with_bundle.admin_form'
+)]
 class EntityTestMulWithBundle extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBaseField.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBaseField.php
index 3c741cb8e884ea2e3deb840b408b33c4201c66c7..ff69c8779353de96f2858cbfeb252b16655f8684 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBaseField.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestMultiValueBaseField.php
@@ -4,30 +4,32 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\views\EntityViewsData;
 
 // cspell:ignore basefield
 
 /**
  * Defines an entity type with a multivalue base field.
- *
- * @ContentEntityType(
- *   id = "entity_test_multivalue_basefield",
- *   label = @Translation("Entity Test with a multivalue base field"),
- *   base_table = "entity_test_multivalue_basefield",
- *   data_table = "entity_test_multivalue_basefield_field_data",
- *   handlers = {
- *     "views_data" = "Drupal\views\EntityViewsData",
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_multivalue_basefield',
+  label: new TranslatableMarkup('Entity Test with a multivalue base field'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'views_data' => EntityViewsData::class,
+  ],
+  base_table: 'entity_test_multivalue_basefield',
+  data_table: 'entity_test_multivalue_basefield_field_data',
+)]
 class EntityTestMultiValueBaseField extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php
index 4b120fcf93937606b20e0cec63cd35c6875d13f5..eedcd79460ef86b78e65262128b0a247788357f6 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNew.php
@@ -4,24 +4,26 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Defines the test entity class for testing definition addition.
  *
  * This entity type is initially not defined. It is enabled when needed to test
  * the related updates.
- *
- * @ContentEntityType(
- *   id = "entity_test_new",
- *   label = @Translation("New test entity"),
- *   base_table = "entity_test_new",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_new',
+  label: new TranslatableMarkup('New test entity'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  base_table: 'entity_test_new',
+)]
 class EntityTestNew extends EntityTest {
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php
index f2b1888fed5da4561cabbff469e3df2b759fe92d..c62d428830bbe61fc603e047272d1a7c7e834b7d 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundle.php
@@ -4,26 +4,29 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\EntityViewsData;
+
 /**
  * Test entity class with no bundle.
- *
- * @ContentEntityType(
- *   id = "entity_test_no_bundle",
- *   label = @Translation("Entity Test without bundle"),
- *   base_table = "entity_test_no_bundle",
- *   handlers = {
- *     "views_data" = "Drupal\views\EntityViewsData"
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "revision_id",
- *   },
- *   admin_permission = "administer entity_test content",
- *   links = {
- *     "add-form" = "/entity_test_no_bundle/add",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_no_bundle',
+  label: new TranslatableMarkup('Entity Test without bundle'),
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'revision_id',
+  ],
+  handlers: [
+    'views_data' => EntityViewsData::class,
+  ],
+  links: [
+    'add-form' => '/entity_test_no_bundle/add',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_no_bundle',
+)]
 class EntityTestNoBundle extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundleWithLabel.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundleWithLabel.php
index ef966a4532ac241f301c9ab2553b3d50d1c3c31c..3d1e9912e7e70dcf65f85f2968fdfde593314ea6 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundleWithLabel.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoBundleWithLabel.php
@@ -4,27 +4,30 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\views\EntityViewsData;
+
 /**
  * Test entity class with no bundle but with label.
- *
- * @ContentEntityType(
- *   id = "entity_test_no_bundle_with_label",
- *   label = @Translation("Entity Test without bundle but with label"),
- *   base_table = "entity_test_no_bundle_with_label",
- *   handlers = {
- *     "views_data" = "Drupal\views\EntityViewsData"
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "name",
- *     "revision" = "revision_id",
- *   },
- *   admin_permission = "administer entity_test content",
- *   links = {
- *     "add-form" = "/entity_test_no_bundle_with_label/add",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_no_bundle_with_label',
+  label: new TranslatableMarkup('Entity Test without bundle but with label'),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'name',
+    'revision' => 'revision_id',
+  ],
+  handlers: [
+    'views_data' => EntityViewsData::class,
+  ],
+  links: [
+    'add-form' => '/entity_test_no_bundle_with_label/add',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_no_bundle_with_label',
+)]
 class EntityTestNoBundleWithLabel extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php
index 23e3e2678c2931746ceecb94b39a36c2386345f0..7382b31a553522fbee41b4d51de4479dd2fe47f2 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoId.php
@@ -4,25 +4,28 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\ContentEntityNullStorage;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_no_id",
- *   label = @Translation("Entity Test without id"),
- *   handlers = {
- *     "storage" = "Drupal\Core\Entity\ContentEntityNullStorage",
- *   },
- *   entity_keys = {
- *     "bundle" = "type",
- *   },
- *   admin_permission = "administer entity_test content",
- *   field_ui_base_route = "entity.entity_test_no_id.admin_form",
- *   links = {
- *     "add-form" = "/entity_test_no_id/add",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_no_id',
+  label: new TranslatableMarkup('Entity Test without id'),
+  entity_keys: [
+    'bundle' => 'type',
+  ],
+  handlers: [
+    'storage' => ContentEntityNullStorage::class,
+  ],
+  links: [
+    'add-form' => '/entity_test_no_id/add',
+  ],
+  admin_permission: 'administer entity_test content',
+  field_ui_base_route: 'entity.entity_test_no_id.admin_form',
+)]
 class EntityTestNoId extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php
index 6b947985a66c0ed112571c5efbe3d861bf181ba6..5c0c1ea16bb86919cba9e1bc70cf188f69a47ea6 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoLabel.php
@@ -4,25 +4,28 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+
 /**
  * Test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_no_label",
- *   label = @Translation("Entity Test without label"),
- *   internal = TRUE,
- *   persistent_cache = FALSE,
- *   base_table = "entity_test_no_label",
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *   },
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_no_label',
+  label: new TranslatableMarkup('Entity Test without label'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+  ],
+  base_table: 'entity_test_no_label',
+  internal: TRUE,
+)]
 class EntityTestNoLabel extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php
index 802ff359f4d19928f47370ba7cf6456e5d115d78..3942b006de24c6f81d6f4e178cb69471dbd87da7 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestNoUuid.php
@@ -4,28 +4,31 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+
 /**
  * Test entity class with revisions but without UUIDs.
- *
- * @ContentEntityType(
- *   id = "entity_test_no_uuid",
- *   label = @Translation("Test entity without UUID"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *   },
- *   base_table = "entity_test_no_uuid",
- *   revision_table = "entity_test_no_uuid_revision",
- *   admin_permission = "administer entity_test content",
- *   persistent_cache = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "vid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_no_uuid',
+  label: new TranslatableMarkup('Test entity without UUID'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'vid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_no_uuid',
+  revision_table: 'entity_test_no_uuid_revision',
+)]
 class EntityTestNoUuid extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
index 1f81e0b7bbee5e5d92563c9ee5685322631b590b..1aa90d50d301fe8c1dd4261b18a40c455875955e 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRev.php
@@ -4,56 +4,66 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\Entity\Form\DeleteMultipleForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
+use Drupal\views\EntityViewsData;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_rev",
- *   label = @Translation("Test entity - revisions"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm",
- *       "delete-multiple-confirm" = \Drupal\Core\Entity\Form\DeleteMultipleForm::class,
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     },
- *   },
- *   base_table = "entity_test_rev",
- *   revision_table = "entity_test_rev_revision",
- *   admin_permission = "administer entity_test content",
- *   show_revision_ui = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "revision" = "revision_id",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_rev/add",
- *     "canonical" = "/entity_test_rev/manage/{entity_test_rev}",
- *     "delete-form" = "/entity_test/delete/entity_test_rev/{entity_test_rev}",
- *     "delete-multiple-form" = "/entity_test_rev/delete_multiple",
- *     "edit-form" = "/entity_test_rev/manage/{entity_test_rev}/edit",
- *     "revision" = "/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/view",
- *     "revision-delete-form" = "/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/delete",
- *     "revision-revert-form" = "/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/revert",
- *     "version-history" = "/entity_test_rev/{entity_test_rev}/revisions",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_rev',
+  label: new TranslatableMarkup('Test entity - revisions'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'revision' => 'revision_id',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'view_builder' => TestViewBuilder::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+      'delete-multiple-confirm' => DeleteMultipleForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'views_data' => EntityViewsData::class,
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+      'revision' => RevisionHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_rev/add',
+    'canonical' => '/entity_test_rev/manage/{entity_test_rev}',
+    'delete-form' => '/entity_test/delete/entity_test_rev/{entity_test_rev}',
+    'delete-multiple-form' => '/entity_test_rev/delete_multiple',
+    'edit-form' => '/entity_test_rev/manage/{entity_test_rev}/edit',
+    'revision' => '/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/view',
+    'revision-delete-form' => '/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/delete',
+    'revision-revert-form' => '/entity_test_rev/{entity_test_rev}/revision/{entity_test_rev_revision}/revert',
+    'version-history' => '/entity_test_rev/{entity_test_rev}/revisions',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_rev',
+  revision_table: 'entity_test_rev_revision', show_revision_ui: TRUE,
+)]
 class EntityTestRev extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRevPub.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRevPub.php
index 0871fcfbad3ff82b5325e75e8b733a0103cc1688..877710005c05821e7f8fd9765484375a88eb8427 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRevPub.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestRevPub.php
@@ -4,57 +4,67 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\Entity\Form\DeleteMultipleForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\EntityPublishedTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestDeleteForm;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_revpub",
- *   label = @Translation("Test entity - revisions and publishing status"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm",
- *       "delete" = "Drupal\entity_test\EntityTestDeleteForm",
- *       "delete-multiple-confirm" = \Drupal\Core\Entity\Form\DeleteMultipleForm::class,
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "route_provider" = {
- *       "html" = \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider::class,
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     },
- *   },
- *   base_table = "entity_test_revpub",
- *   revision_table = "entity_test_revpub_revision",
- *   admin_permission = "administer entity_test content",
- *   show_revision_ui = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "revision" = "revision_id",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *     "published" = "status",
- *   },
- *   links = {
- *     "add-form" = "/entity_test_revpub/add",
- *     "canonical" = "/entity_test_revpub/manage/{entity_test_revpub}",
- *     "delete-form" = "/entity_test/delete/entity_test_revpub/{entity_test_revpub}",
- *     "delete-multiple-form" = "/entity_test_revpub/delete_multiple",
- *     "edit-form" = "/entity_test_revpub/manage/{entity_test_revpub}/edit",
- *     "revision" = "/entity_test_revpub/{entity_test_revpub}/revision/{entity_test_revpub_revision}/view",
- *     "revision-delete-form" = "/entity_test_revpub/{entity_test_revpub}/revision/{entity_test_revpub_revision}/delete",
- *     "revision-revert-form" = "/entity_test_revpub/{entity_test_revpub}/revision/{entity_test_revpub_revision}/revert",
- *     "version-history" = "/entity_test_revpub/{entity_test_revpub}/revisions",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_revpub',
+  label: new TranslatableMarkup('Test entity - revisions and publishing status'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'revision' => 'revision_id',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+    'published' => 'status',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'view_builder' => TestViewBuilder::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+      'delete' => EntityTestDeleteForm::class,
+      'delete-multiple-confirm' => DeleteMultipleForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+      'revision' => RevisionHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_revpub/add',
+    'canonical' => '/entity_test_revpub/manage/{entity_test_revpub}',
+    'delete-form' => '/entity_test/delete/entity_test_revpub/{entity_test_revpub}',
+    'delete-multiple-form' => '/entity_test_revpub/delete_multiple',
+    'edit-form' => '/entity_test_revpub/manage/{entity_test_revpub}/edit',
+    'revision' => '/entity_test_revpub/{entity_test_revpub}/revision/{entity_test_revpub_revision}/view',
+    'revision-delete-form' => '/entity_test_revpub/{entity_test_revpub}/revision/{entity_test_revpub_revision}/delete',
+    'revision-revert-form' => '/entity_test_revpub/{entity_test_revpub}/revision/{entity_test_revpub_revision}/revert',
+    'version-history' => '/entity_test_revpub/{entity_test_revpub}/revisions',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_revpub',
+  revision_table: 'entity_test_revpub_revision',
+  show_revision_ui: TRUE,
+)]
 class EntityTestRevPub extends EntityTestRev implements EntityPublishedInterface {
 
   use EntityPublishedTrait;
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
index c19ad18fd29f35f4e45830c48f7d0fad3a3d3d77..2db1fe8bc0197d4462f48bbd253e89ca330d2205 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestStringId.php
@@ -4,40 +4,44 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestForm;
 
 /**
  * Defines a test entity class with a string ID.
- *
- * @ContentEntityType(
- *   id = "entity_test_string_id",
- *   label = @Translation("Test entity with string_id"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_string",
- *   admin_permission = "administer entity_test content",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *   },
- *   links = {
- *     "canonical" = "/entity_test_string_id/manage/{entity_test_string_id}",
- *     "add-form" = "/entity_test_string_id/add",
- *     "edit-form" = "/entity_test_string_id/manage/{entity_test_string_id}",
- *   },
- *   field_ui_base_route = "entity.entity_test_string_id.admin_form",
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_string_id',
+  label: new TranslatableMarkup('Test entity with string_id'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'canonical' => '/entity_test_string_id/manage/{entity_test_string_id}',
+    'add-form' => '/entity_test_string_id/add',
+    'edit-form' => '/entity_test_string_id/manage/{entity_test_string_id}',
+  ],
+  admin_permission: 'administer entity_test content',
+  base_table: 'entity_test_string',
+  field_ui_base_route: 'entity.entity_test_string_id.admin_form',
+)]
 class EntityTestStringId extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestUniqueConstraint.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestUniqueConstraint.php
index 43ce759e6ab07febaf0aa7f61729ef423f9c0df1..0e23aa61688a1f1e96aa339b9a552cbf3c036bba 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestUniqueConstraint.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestUniqueConstraint.php
@@ -4,31 +4,36 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\content_translation\ContentTranslationHandler;
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestForm;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
 
 /**
  * Defines a test entity class for unique constraint.
- *
- * @ContentEntityType(
- *   id = "entity_test_unique_constraint",
- *   label = @Translation("unique field entity"),
- *   handlers = {
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\entity_test\EntityTestForm"
- *     },
- *     "translation" = "Drupal\content_translation\ContentTranslationHandler",
- *   },
- *   base_table = "entity_test_unique_constraint",
- *   data_table = "entity_test_unique_constraint_data",
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_unique_constraint',
+  label: new TranslatableMarkup('unique field entity'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+  ],
+  handlers: [
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => EntityTestForm::class,
+    ],
+    'translation' => ContentTranslationHandler::class,
+  ],
+  base_table: 'entity_test_unique_constraint',
+  data_table: 'entity_test_unique_constraint_data',
+)]
 class EntityTestUniqueConstraint extends EntityTest {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php
index 4d22ff4e627ad2f8a6178698668170f7831a4891..a03358e617f99ccc97f927695b92b749f40aec3b 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestViewBuilder.php
@@ -4,27 +4,31 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestViewBuilderOverriddenView;
+
 /**
  * Test entity class for testing a view builder.
- *
- * @ContentEntityType(
- *   id = "entity_test_view_builder",
- *   label = @Translation("Entity Test view builder"),
- *   handlers = {
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilderOverriddenView",
- *   },
- *   base_table = "entity_test_view_builder",
- *   render_cache = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "label" = "name",
- *     "bundle" = "type",
- *     "langcode" = "langcode",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_view_builder',
+  label: new TranslatableMarkup('Entity Test view builder'),
+  render_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'label' => 'name',
+    'bundle' => 'type',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => EntityTestAccessControlHandler::class,
+    'view_builder' => EntityTestViewBuilderOverriddenView::class,
+  ],
+  base_table: 'entity_test_view_builder',
+)]
 class EntityTestViewBuilder extends EntityTest {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php
index 9171ff7462aae839526033a3117503cd0d9cbfef..407ea3eb7718648abf64522861d01aae10db0ed9 100644
--- a/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php
+++ b/core/modules/system/tests/modules/entity_test/src/Entity/EntityTestWithBundle.php
@@ -4,51 +4,58 @@
 
 namespace Drupal\entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\Entity\EntityDeleteForm;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test\EntityTestAccessControlHandler;
+use Drupal\entity_test\EntityTestListBuilder;
+use Drupal\entity_test\EntityTestViewBuilder as TestViewBuilder;
 
 /**
  * Defines the Test entity with bundle entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_with_bundle",
- *   label = @Translation("Test entity with bundle"),
- *   handlers = {
- *     "list_builder" = "Drupal\entity_test\EntityTestListBuilder",
- *     "view_builder" = "Drupal\entity_test\EntityTestViewBuilder",
- *     "access" = "Drupal\entity_test\EntityTestAccessControlHandler",
- *     "form" = {
- *       "default" = "\Drupal\Core\Entity\ContentEntityForm",
- *       "delete" = "\Drupal\Core\Entity\EntityDeleteForm"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider",
- *     },
- *   },
- *   base_table = "entity_test_with_bundle",
- *   data_table = "entity_test_with_bundle_field_data",
- *   admin_permission = "administer entity_test_with_bundle content",
- *   persistent_cache = FALSE,
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   bundle_entity_type = "entity_test_bundle",
- *   links = {
- *     "canonical" = "/entity_test_with_bundle/{entity_test_with_bundle}",
- *     "add-page" = "/entity_test_with_bundle/add",
- *     "add-form" = "/entity_test_with_bundle/add/{entity_test_bundle}",
- *     "edit-form" = "/entity_test_with_bundle/{entity_test_with_bundle}/edit",
- *     "delete-form" = "/entity_test_with_bundle/{entity_test_with_bundle}/delete",
- *     "create" = "/entity_test_with_bundle",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_with_bundle',
+  label: new TranslatableMarkup('Test entity with bundle'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'list_builder' => EntityTestListBuilder::class,
+    'view_builder' => TestViewBuilder::class,
+    'access' => EntityTestAccessControlHandler::class,
+    'form' => [
+      'default' => ContentEntityForm::class,
+      'delete' => EntityDeleteForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'canonical' => '/entity_test_with_bundle/{entity_test_with_bundle}',
+    'add-page' => '/entity_test_with_bundle/add',
+    'add-form' => '/entity_test_with_bundle/add/{entity_test_bundle}',
+    'edit-form' => '/entity_test_with_bundle/{entity_test_with_bundle}/edit',
+    'delete-form' => '/entity_test_with_bundle/{entity_test_with_bundle}/delete',
+    'create' => '/entity_test_with_bundle',
+  ],
+  admin_permission: 'administer entity_test_with_bundle content',
+  bundle_entity_type: 'entity_test_bundle',
+  base_table: 'entity_test_with_bundle',
+  data_table: 'entity_test_with_bundle_field_data',
+  translatable: TRUE,
+)]
 class EntityTestWithBundle extends ContentEntityBase {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLog.php b/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLog.php
index 92b91c0027eca87391b1a5cfe9d8bc89edd02052..1bbcf5030d62dbe4b03e9ba79f36bd295e52a4e2 100644
--- a/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLog.php
+++ b/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLog.php
@@ -4,54 +4,62 @@
 
 namespace Drupal\entity_test_revlog\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\entity_test_revlog\EntityTestRevlogAccessControlHandler;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul_revlog",
- *   label = @Translation("Test entity - data table, revisions log"),
- *   handlers = {
- *     "access" = \Drupal\entity_test_revlog\EntityTestRevlogAccessControlHandler::class,
- *     "form" = {
- *       "default" = \Drupal\Core\Entity\ContentEntityForm::class,
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "route_provider" = {
- *       "html" = \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider::class,
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     },
- *   },
- *   base_table = "entity_test_mul_revlog",
- *   data_table = "entity_test_mul_revlog_field_data",
- *   revision_table = "entity_test_mul_revlog_revision",
- *   revision_data_table = "entity_test_mul_revlog_field_revision",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "revision" = "revision_id",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message"
- *   },
- *   links = {
- *     "add-form" = "/entity_test_mul_revlog/add",
- *     "canonical" = "/entity_test_mul_revlog/manage/{entity_test_mul_revlog}",
- *     "delete-form" = "/entity_test/delete/entity_test_mul_revlog/{entity_test_mul_revlog}",
- *     "edit-form" = "/entity_test_mul_revlog/manage/{entity_test_mul_revlog}/edit",
- *     "revision" = "/entity_test_mul_revlog/{entity_test_mul_revlog}/revision/{entity_test_mul_revlog_revision}/view",
- *     "revision-delete-form" = "/entity_test_mul_revlog/{entity_test_mul_revlog}/revision/{entity_test_mul_revlog_revision}/delete",
- *     "revision-revert-form" = "/entity_test_mul_revlog/{entity_test_mul_revlog}/revision/{entity_test_mul_revlog_revision}/revert",
- *     "version-history" = "/entity_test_mul_revlog/{entity_test_mul_revlog}/revisions",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul_revlog',
+  label: new TranslatableMarkup('Test entity - data table, revisions log'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'revision' => 'revision_id',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'access' => EntityTestRevlogAccessControlHandler::class,
+    'form' => [
+      'default' => ContentEntityForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+      'revision' => RevisionHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_mul_revlog/add',
+    'canonical' => '/entity_test_mul_revlog/manage/{entity_test_mul_revlog}',
+    'delete-form' => '/entity_test/delete/entity_test_mul_revlog/{entity_test_mul_revlog}',
+    'edit-form' => '/entity_test_mul_revlog/manage/{entity_test_mul_revlog}/edit',
+    'revision' => '/entity_test_mul_revlog/{entity_test_mul_revlog}/revision/{entity_test_mul_revlog_revision}/view',
+    'revision-delete-form' => '/entity_test_mul_revlog/{entity_test_mul_revlog}/revision/{entity_test_mul_revlog_revision}/delete',
+    'revision-revert-form' => '/entity_test_mul_revlog/{entity_test_mul_revlog}/revision/{entity_test_mul_revlog_revision}/revert',
+    'version-history' => '/entity_test_mul_revlog/{entity_test_mul_revlog}/revisions',
+  ],
+  base_table: 'entity_test_mul_revlog',
+  data_table: 'entity_test_mul_revlog_field_data',
+  revision_table: 'entity_test_mul_revlog_revision',
+  revision_data_table: 'entity_test_mul_revlog_field_revision',
+  translatable: TRUE,
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ],
+)]
 class EntityTestMulWithRevisionLog extends EntityTestWithRevisionLog {
 
 }
diff --git a/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLogPub.php b/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLogPub.php
index 557835e73c0ef4461f90ed7ce493587e5dc2a08d..6c1f7aaf082a9d716cd7671133773310c03fd22e 100644
--- a/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLogPub.php
+++ b/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestMulWithRevisionLogPub.php
@@ -4,37 +4,38 @@
 
 namespace Drupal\entity_test_revlog\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityPublishedInterface;
 use Drupal\Core\Entity\EntityPublishedTrait;
 use Drupal\Core\Entity\EntityTypeInterface;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_mul_revlog_pub",
- *   label = @Translation("Test entity - data table, revisions log, publishing status"),
- *   base_table = "entity_test_mul_revlog_pub",
- *   data_table = "entity_test_mul_revlog_pub_field_data",
- *   revision_table = "entity_test_mul_revlog_pub_revision",
- *   revision_data_table = "entity_test_mul_revlog_pub_field_revision",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "revision" = "revision_id",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *     "published" = "status",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message"
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_mul_revlog_pub',
+  label: new TranslatableMarkup('Test entity - data table, revisions log, publishing status'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'revision' => 'revision_id',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+    'published' => 'status',
+  ],
+  base_table: 'entity_test_mul_revlog_pub',
+  data_table: 'entity_test_mul_revlog_pub_field_data',
+  revision_table: 'entity_test_mul_revlog_pub_revision',
+  revision_data_table: 'entity_test_mul_revlog_pub_field_revision',
+  translatable: TRUE,
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ],
+)]
 class EntityTestMulWithRevisionLogPub extends EntityTestWithRevisionLog implements EntityPublishedInterface {
 
   use EntityPublishedTrait;
diff --git a/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestWithRevisionLog.php b/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestWithRevisionLog.php
index c8319fd9e02f6707e04068978872ad9a56bf3f8e..8a4f7b9afee4a69f72156fee9de28263f19b8e0f 100644
--- a/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestWithRevisionLog.php
+++ b/core/modules/system/tests/modules/entity_test_revlog/src/Entity/EntityTestWithRevisionLog.php
@@ -4,56 +4,63 @@
 
 namespace Drupal\entity_test_revlog\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\Entity\ContentEntityForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Entity\RevisionableContentEntityBase;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\entity_test_revlog\EntityTestRevlogAccessControlHandler;
 
 /**
  * Defines the test entity class.
- *
- * @ContentEntityType(
- *   id = "entity_test_revlog",
- *   label = @Translation("Test entity - revisions log"),
- *   handlers = {
- *     "access" = "Drupal\entity_test_revlog\EntityTestRevlogAccessControlHandler",
- *     "form" = {
- *       "default" = \Drupal\Core\Entity\ContentEntityForm::class,
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "route_provider" = {
- *       "html" = \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider::class,
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     },
- *   },
- *   base_table = "entity_test_revlog",
- *   revision_table = "entity_test_revlog_revision",
- *   translatable = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "revision" = "revision_id",
- *     "bundle" = "type",
- *     "label" = "name",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message"
- *   },
- *   links = {
- *     "add-form" = "/entity_test_revlog/add",
- *     "canonical" = "/entity_test_revlog/manage/{entity_test_revlog}",
- *     "delete-form" = "/entity_test/delete/entity_test_revlog/{entity_test_revlog}",
- *     "delete-multiple-form" = "/entity_test_revlog/delete_multiple",
- *     "edit-form" = "/entity_test_revlog/manage/{entity_test_revlog}/edit",
- *     "revision" = "/entity_test_revlog/{entity_test_revlog}/revision/{entity_test_revlog_revision}/view",
- *     "revision-delete-form" = "/entity_test_revlog/{entity_test_revlog}/revision/{entity_test_revlog_revision}/delete",
- *     "revision-revert-form" = "/entity_test_revlog/{entity_test_revlog}/revision/{entity_test_revlog_revision}/revert",
- *     "version-history" = "/entity_test_revlog/{entity_test_revlog}/revisions",
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_revlog',
+  label: new TranslatableMarkup('Test entity - revisions log'),
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'revision' => 'revision_id',
+    'bundle' => 'type',
+    'label' => 'name',
+  ],
+  handlers: [
+    'access' => EntityTestRevlogAccessControlHandler::class,
+    'form' => [
+      'default' => ContentEntityForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'route_provider' => [
+      'html' => DefaultHtmlRouteProvider::class,
+      'revision' => RevisionHtmlRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/entity_test_revlog/add',
+    'canonical' => '/entity_test_revlog/manage/{entity_test_revlog}',
+    'delete-form' => '/entity_test/delete/entity_test_revlog/{entity_test_revlog}',
+    'delete-multiple-form' => '/entity_test_revlog/delete_multiple',
+    'edit-form' => '/entity_test_revlog/manage/{entity_test_revlog}/edit',
+    'revision' => '/entity_test_revlog/{entity_test_revlog}/revision/{entity_test_revlog_revision}/view',
+    'revision-delete-form' => '/entity_test_revlog/{entity_test_revlog}/revision/{entity_test_revlog_revision}/delete',
+    'revision-revert-form' => '/entity_test_revlog/{entity_test_revlog}/revision/{entity_test_revlog_revision}/revert',
+    'version-history' => '/entity_test_revlog/{entity_test_revlog}/revisions',
+  ],
+  base_table: 'entity_test_revlog',
+  revision_table: 'entity_test_revlog_revision',
+  translatable: FALSE,
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ],
+)]
 class EntityTestWithRevisionLog extends RevisionableContentEntityBase {
 
   /**
diff --git a/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php b/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php
index f3eec50fd0405ffcde759d88cd7df6b67f66c67c..0b4c49504553867d3217fb622995f91436ca88e4 100644
--- a/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php
+++ b/core/modules/system/tests/modules/entity_test_update/src/Entity/EntityTestUpdate.php
@@ -4,11 +4,14 @@
 
 namespace Drupal\entity_test_update\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\entity_test_update\EntityTestUpdateStorage;
+use Drupal\entity_test_update\EntityTestUpdateStorageSchema;
 
 /**
  * Defines the test entity class for testing definition and schema updates.
@@ -17,26 +20,27 @@
  * an update test it can be made revisionable and translatable using the helper
  * methods from
  * \Drupal\Tests\system\Functional\Entity\Traits\EntityDefinitionTestTrait.
- *
- * @ContentEntityType(
- *   id = "entity_test_update",
- *   label = @Translation("Test entity update"),
- *   handlers = {
- *     "storage_schema" = "Drupal\entity_test_update\EntityTestUpdateStorageSchema",
- *     "storage" = "Drupal\entity_test_update\EntityTestUpdateStorage",
- *   },
- *   base_table = "entity_test_update",
- *   persistent_cache = FALSE,
- *   entity_keys = {
- *     "id" = "id",
- *     "uuid" = "uuid",
- *     "bundle" = "type",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *   },
- *   content_translation_ui_skip = TRUE,
- * )
  */
+#[ContentEntityType(
+  id: 'entity_test_update',
+  label: new TranslatableMarkup('Test entity update'),
+  persistent_cache: FALSE,
+  entity_keys: [
+    'id' => 'id',
+    'uuid' => 'uuid',
+    'bundle' => 'type',
+    'label' => 'name',
+    'langcode' => 'langcode',
+  ],
+  handlers: [
+    'storage_schema' => EntityTestUpdateStorageSchema::class,
+    'storage' => EntityTestUpdateStorage::class,
+  ],
+  base_table: 'entity_test_update',
+  additional: [
+    'content_translation_ui_skip' => TRUE,
+  ],
+)]
 class EntityTestUpdate extends ContentEntityBase {
 
   /**
diff --git a/core/modules/system/tests/modules/module_installer_config_test/src/Entity/TestConfigType.php b/core/modules/system/tests/modules/module_installer_config_test/src/Entity/TestConfigType.php
index b43f102e3915bec7d613927a8050fb2b1343efd2..c842f64c5c783450a1c8cf3a0db91c3d85090cb0 100644
--- a/core/modules/system/tests/modules/module_installer_config_test/src/Entity/TestConfigType.php
+++ b/core/modules/system/tests/modules/module_installer_config_test/src/Entity/TestConfigType.php
@@ -4,28 +4,30 @@
 
 namespace Drupal\module_installer_config_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 
 /**
  * Defines a configuration-based entity type used for testing.
- *
- * @ConfigEntityType(
- *   id = "test_config_type",
- *   label = @Translation("Test entity type"),
- *   handlers = {
- *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder"
- *   },
- *   admin_permission = "administer modules",
- *   config_prefix = "type",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "name"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'test_config_type',
+  label: new TranslatableMarkup('Test entity type'),
+  config_prefix: 'type',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'name',
+  ],
+  handlers: [
+    'list_builder' => EntityListBuilder::class,
+  ],
+  admin_permission: 'administer modules',
+  config_export: [
+    'id',
+    'label',
+  ],
+)]
 class TestConfigType extends ConfigEntityBase {
 }
diff --git a/core/modules/system/tests/src/Kernel/Entity/EntityLabelTest.php b/core/modules/system/tests/src/Kernel/Entity/EntityLabelTest.php
index 3f29865ac954e25fe99619921387c9ee7c0a4f47..84add63741e00f2d2e9a4334986e62b2e04a9d37 100644
--- a/core/modules/system/tests/src/Kernel/Entity/EntityLabelTest.php
+++ b/core/modules/system/tests/src/Kernel/Entity/EntityLabelTest.php
@@ -4,7 +4,8 @@
 
 namespace Drupal\Tests\system\Kernel\Entity;
 
-use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
+use Drupal\Core\Entity\Attribute\EntityType;
+use Drupal\Core\Plugin\Discovery\AttributeClassDiscovery;
 use Drupal\KernelTests\KernelTestBase;
 
 /**
@@ -22,10 +23,10 @@ public function testEntityLabelCasing(): void {
     $modules = scandir($base_directory);
     $paths = [];
     foreach ($modules as $module) {
-      $paths["\Drupal\\{$module}\Entity"] = $base_directory . $module . '/src/';
+      $paths["Drupal\\{$module}"] = $base_directory . $module . '/src/';
     }
     $namespaces = new \ArrayObject($paths);
-    $discovery = new AnnotatedClassDiscovery('Entity', $namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
+    $discovery = new AttributeClassDiscovery('Entity', $namespaces, EntityType::class);
     $definitions = $discovery->getDefinitions();
 
     foreach ($definitions as $definition) {
diff --git a/core/modules/taxonomy/src/Entity/Term.php b/core/modules/taxonomy/src/Entity/Term.php
index a0824d755be6de7bf2a3a5be3f76574e8e20a59f..d96aaa83a7ae1a1636fe54cadcab8ddcaca2c080 100644
--- a/core/modules/taxonomy/src/Entity/Term.php
+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -2,85 +2,98 @@
 
 namespace Drupal\taxonomy\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\Core\Entity\EntityViewBuilder;
+use Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider;
+use Drupal\Core\Entity\Form\RevisionRevertForm;
+use Drupal\Core\Entity\Form\RevisionDeleteForm;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\EditorialContentEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
 use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\taxonomy\Form\TermDeleteForm;
+use Drupal\taxonomy\TermAccessControlHandler;
+use Drupal\taxonomy\TermForm;
 use Drupal\taxonomy\TermInterface;
+use Drupal\taxonomy\TermStorage;
+use Drupal\taxonomy\TermStorageSchema;
+use Drupal\taxonomy\TermTranslationHandler;
+use Drupal\taxonomy\TermViewsData;
 use Drupal\user\StatusItem;
 
 /**
  * Defines the taxonomy term entity.
- *
- * @ContentEntityType(
- *   id = "taxonomy_term",
- *   label = @Translation("Taxonomy term"),
- *   label_collection = @Translation("Taxonomy terms"),
- *   label_singular = @Translation("taxonomy term"),
- *   label_plural = @Translation("taxonomy terms"),
- *   label_count = @PluralTranslation(
- *     singular = "@count taxonomy term",
- *     plural = "@count taxonomy terms",
- *   ),
- *   bundle_label = @Translation("Vocabulary"),
- *   handlers = {
- *     "storage" = "Drupal\taxonomy\TermStorage",
- *     "storage_schema" = "Drupal\taxonomy\TermStorageSchema",
- *     "view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
- *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
- *     "access" = "Drupal\taxonomy\TermAccessControlHandler",
- *     "views_data" = "Drupal\taxonomy\TermViewsData",
- *     "form" = {
- *       "default" = "Drupal\taxonomy\TermForm",
- *       "delete" = "Drupal\taxonomy\Form\TermDeleteForm",
- *       "revision-delete" = \Drupal\Core\Entity\Form\RevisionDeleteForm::class,
- *       "revision-revert" = \Drupal\Core\Entity\Form\RevisionRevertForm::class,
- *     },
- *     "route_provider" = {
- *       "revision" = \Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider::class,
- *     },
- *     "translation" = "Drupal\taxonomy\TermTranslationHandler"
- *   },
- *   base_table = "taxonomy_term_data",
- *   data_table = "taxonomy_term_field_data",
- *   revision_table = "taxonomy_term_revision",
- *   revision_data_table = "taxonomy_term_field_revision",
- *   show_revision_ui = TRUE,
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "tid",
- *     "revision" = "revision_id",
- *     "bundle" = "vid",
- *     "label" = "name",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid",
- *     "published" = "status",
- *   },
- *   revision_metadata_keys = {
- *     "revision_user" = "revision_user",
- *     "revision_created" = "revision_created",
- *     "revision_log_message" = "revision_log_message",
- *   },
- *   bundle_entity_type = "taxonomy_vocabulary",
- *   field_ui_base_route = "entity.taxonomy_vocabulary.overview_form",
- *   common_reference_target = TRUE,
- *   links = {
- *     "canonical" = "/taxonomy/term/{taxonomy_term}",
- *     "delete-form" = "/taxonomy/term/{taxonomy_term}/delete",
- *     "edit-form" = "/taxonomy/term/{taxonomy_term}/edit",
- *     "create" = "/taxonomy/term",
- *     "revision" = "/taxonomy/term/{taxonomy_term}/revision/{taxonomy_term_revision}/view",
- *     "revision-delete-form" = "/taxonomy/term/{taxonomy_term}/revision/{taxonomy_term_revision}/delete",
- *     "revision-revert-form" = "/taxonomy/term/{taxonomy_term}/revision/{taxonomy_term_revision}/revert",
- *     "version-history" = "/taxonomy/term/{taxonomy_term}/revisions",
- *   },
- *   permission_granularity = "bundle",
- *   collection_permission = "access taxonomy overview",
- *   constraints = {
- *     "TaxonomyHierarchy" = {}
- *   }
- * )
  */
+#[ContentEntityType(
+  id: 'taxonomy_term',
+  label: new TranslatableMarkup('Taxonomy term'),
+  label_collection: new TranslatableMarkup('Taxonomy terms'),
+  label_singular: new TranslatableMarkup('taxonomy term'),
+  label_plural: new TranslatableMarkup('taxonomy terms'),
+  entity_keys: [
+    'id' => 'tid',
+    'revision' => 'revision_id',
+    'bundle' => 'vid',
+    'label' => 'name',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+    'published' => 'status',
+  ],
+  handlers: [
+    'storage' => TermStorage::class,
+    'storage_schema' => TermStorageSchema::class,
+    'view_builder' => EntityViewBuilder::class,
+    'list_builder' => EntityListBuilder::class,
+    'access' => TermAccessControlHandler::class,
+    'views_data' => TermViewsData::class,
+    'form' => [
+      'default' => TermForm::class,
+      'delete' => TermDeleteForm::class,
+      'revision-delete' => RevisionDeleteForm::class,
+      'revision-revert' => RevisionRevertForm::class,
+    ],
+    'route_provider' => [
+      'revision' => RevisionHtmlRouteProvider::class,
+    ],
+    'translation' => TermTranslationHandler::class,
+  ],
+  links: [
+    'canonical' => '/taxonomy/term/{taxonomy_term}',
+    'delete-form' => '/taxonomy/term/{taxonomy_term}/delete',
+    'edit-form' => '/taxonomy/term/{taxonomy_term}/edit',
+    'create' => '/taxonomy/term',
+    'revision' => '/taxonomy/term/{taxonomy_term}/revision/{taxonomy_term_revision}/view',
+    'revision-delete-form' => '/taxonomy/term/{taxonomy_term}/revision/{taxonomy_term_revision}/delete',
+    'revision-revert-form' => '/taxonomy/term/{taxonomy_term}/revision/{taxonomy_term_revision}/revert',
+    'version-history' => '/taxonomy/term/{taxonomy_term}/revisions',
+  ],
+  collection_permission: 'access taxonomy overview',
+  permission_granularity: 'bundle',
+  bundle_entity_type: 'taxonomy_vocabulary',
+  bundle_label: new TranslatableMarkup('Vocabulary'),
+  base_table: 'taxonomy_term_data',
+  data_table: 'taxonomy_term_field_data',
+  revision_table: 'taxonomy_term_revision',
+  revision_data_table: 'taxonomy_term_field_revision',
+  translatable: TRUE,
+  show_revision_ui: TRUE,
+  label_count: [
+    'singular' => '@count taxonomy term',
+    'plural' => '@count taxonomy terms',
+  ],
+  field_ui_base_route: 'entity.taxonomy_vocabulary.overview_form',
+  common_reference_target: TRUE,
+  constraints: [
+    'TaxonomyHierarchy' => [],
+  ],
+  revision_metadata_keys: [
+    'revision_user' => 'revision_user',
+    'revision_created' => 'revision_created',
+    'revision_log_message' => 'revision_log_message',
+  ],
+)]
 class Term extends EditorialContentEntityBase implements TermInterface {
 
   /**
diff --git a/core/modules/taxonomy/src/Entity/Vocabulary.php b/core/modules/taxonomy/src/Entity/Vocabulary.php
index 790a3744c8e1ac7e8d526f3f01e7ecafe789ebb1..e254e8ad0b45ea7899f2114d0dfc4ba107cdbf1e 100644
--- a/core/modules/taxonomy/src/Entity/Vocabulary.php
+++ b/core/modules/taxonomy/src/Entity/Vocabulary.php
@@ -2,65 +2,75 @@
 
 namespace Drupal\taxonomy\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBundleBase;
 use Drupal\Core\Entity\EntityStorageInterface;
+use Drupal\taxonomy\Entity\Routing\VocabularyRouteProvider;
+use Drupal\taxonomy\Form\OverviewTerms;
+use Drupal\taxonomy\Form\VocabularyDeleteForm;
+use Drupal\taxonomy\Form\VocabularyResetForm;
+use Drupal\taxonomy\VocabularyAccessControlHandler;
+use Drupal\taxonomy\VocabularyForm;
 use Drupal\taxonomy\VocabularyInterface;
+use Drupal\taxonomy\VocabularyListBuilder;
+use Drupal\taxonomy\VocabularyStorage;
+use Drupal\user\Entity\EntityPermissionsRouteProvider;
 
 /**
  * Defines the taxonomy vocabulary entity.
- *
- * @ConfigEntityType(
- *   id = "taxonomy_vocabulary",
- *   label = @Translation("Taxonomy vocabulary"),
- *   label_singular = @Translation("vocabulary"),
- *   label_plural = @Translation("vocabularies"),
- *   label_collection = @Translation("Taxonomy"),
- *   label_count = @PluralTranslation(
- *     singular = "@count vocabulary",
- *     plural = "@count vocabularies"
- *   ),
- *   handlers = {
- *     "storage" = "Drupal\taxonomy\VocabularyStorage",
- *     "list_builder" = "Drupal\taxonomy\VocabularyListBuilder",
- *     "access" = "Drupal\taxonomy\VocabularyAccessControlHandler",
- *     "form" = {
- *       "default" = "Drupal\taxonomy\VocabularyForm",
- *       "reset" = "Drupal\taxonomy\Form\VocabularyResetForm",
- *       "delete" = "Drupal\taxonomy\Form\VocabularyDeleteForm",
- *       "overview" = "Drupal\taxonomy\Form\OverviewTerms"
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\taxonomy\Entity\Routing\VocabularyRouteProvider",
- *       "permissions" = "Drupal\user\Entity\EntityPermissionsRouteProvider",
- *     }
- *   },
- *   admin_permission = "administer taxonomy",
- *   collection_permission = "access taxonomy overview",
- *   config_prefix = "vocabulary",
- *   bundle_of = "taxonomy_term",
- *   entity_keys = {
- *     "id" = "vid",
- *     "label" = "name",
- *     "weight" = "weight"
- *   },
- *   links = {
- *     "add-form" = "/admin/structure/taxonomy/add",
- *     "delete-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/delete",
- *     "reset-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/reset",
- *     "overview-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview",
- *     "edit-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}",
- *     "entity-permissions-form" = "/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview/permissions",
- *     "collection" = "/admin/structure/taxonomy",
- *   },
- *   config_export = {
- *     "name",
- *     "vid",
- *     "description",
- *     "weight",
- *     "new_revision",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'taxonomy_vocabulary',
+  label: new TranslatableMarkup('Taxonomy vocabulary'),
+  label_collection: new TranslatableMarkup('Taxonomy'),
+  label_singular: new TranslatableMarkup('vocabulary'),
+  label_plural: new TranslatableMarkup('vocabularies'),
+  config_prefix: 'vocabulary',
+  entity_keys: [
+    'id' => 'vid',
+    'label' => 'name',
+    'weight' => 'weight',
+  ],
+  handlers: [
+    'storage' => VocabularyStorage::class,
+    'list_builder' => VocabularyListBuilder::class,
+    'access' => VocabularyAccessControlHandler::class,
+    'form' => [
+      'default' => VocabularyForm::class,
+      'reset' => VocabularyResetForm::class,
+      'delete' => VocabularyDeleteForm::class,
+      'overview' => OverviewTerms::class,
+    ],
+    'route_provider' => [
+      'html' => VocabularyRouteProvider::class,
+      'permissions' => EntityPermissionsRouteProvider::class,
+    ],
+  ],
+  links: [
+    'add-form' => '/admin/structure/taxonomy/add',
+    'delete-form' => '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/delete',
+    'reset-form' => '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/reset',
+    'overview-form' => '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview',
+    'edit-form' => '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}',
+    'entity-permissions-form' => '/admin/structure/taxonomy/manage/{taxonomy_vocabulary}/overview/permissions',
+    'collection' => '/admin/structure/taxonomy',
+  ],
+  admin_permission: 'administer taxonomy',
+  collection_permission: 'access taxonomy overview',
+  bundle_of: 'taxonomy_term',
+  label_count: [
+    'singular' => '@count vocabulary',
+    'plural' => '@count vocabularies',
+  ],
+  config_export: [
+    'name',
+    'vid',
+    'description',
+    'weight',
+    'new_revision',
+  ],
+)]
 class Vocabulary extends ConfigEntityBundleBase implements VocabularyInterface {
 
   /**
diff --git a/core/modules/user/src/Entity/Role.php b/core/modules/user/src/Entity/Role.php
index 62890447801d6260e7d8e80e4206b0c5cd4f38ca..267a75d5408cd3bfc7ed88cfdacd05381a9d21ef 100644
--- a/core/modules/user/src/Entity/Role.php
+++ b/core/modules/user/src/Entity/Role.php
@@ -4,55 +4,60 @@
 
 use Drupal\Core\Config\Action\Attribute\ActionMethod;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityDeleteForm;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\user\RoleAccessControlHandler;
+use Drupal\user\RoleForm;
 use Drupal\user\RoleInterface;
+use Drupal\user\RoleListBuilder;
+use Drupal\user\RoleStorage;
 
 /**
  * Defines the user role entity class.
- *
- * @ConfigEntityType(
- *   id = "user_role",
- *   label = @Translation("Role"),
- *   label_collection = @Translation("Roles"),
- *   label_singular = @Translation("role"),
- *   label_plural = @Translation("roles"),
- *   label_count = @PluralTranslation(
- *     singular = "@count role",
- *     plural = "@count roles",
- *   ),
- *   handlers = {
- *     "storage" = "Drupal\user\RoleStorage",
- *     "access" = "Drupal\user\RoleAccessControlHandler",
- *     "list_builder" = "Drupal\user\RoleListBuilder",
- *     "form" = {
- *       "default" = "Drupal\user\RoleForm",
- *       "delete" = "Drupal\Core\Entity\EntityDeleteForm"
- *     }
- *   },
- *   admin_permission = "administer permissions",
- *   config_prefix = "role",
- *   static_cache = TRUE,
- *   entity_keys = {
- *     "id" = "id",
- *     "weight" = "weight",
- *     "label" = "label"
- *   },
- *   links = {
- *     "delete-form" = "/admin/people/roles/manage/{user_role}/delete",
- *     "edit-form" = "/admin/people/roles/manage/{user_role}",
- *     "edit-permissions-form" = "/admin/people/permissions/{user_role}",
- *     "collection" = "/admin/people/roles",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "weight",
- *     "is_admin",
- *     "permissions",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'user_role',
+  label: new TranslatableMarkup('Role'),
+  label_collection: new TranslatableMarkup('Roles'),
+  label_singular: new TranslatableMarkup('role'),
+  label_plural: new TranslatableMarkup('roles'),
+  config_prefix: 'role',
+  static_cache: TRUE,
+  entity_keys: [
+    'id' => 'id',
+    'weight' => 'weight',
+    'label' => 'label',
+  ],
+  handlers: [
+    'storage' => RoleStorage::class,
+    'access' => RoleAccessControlHandler::class,
+    'list_builder' => RoleListBuilder::class,
+    'form' => [
+      'default' => RoleForm::class,
+      'delete' => EntityDeleteForm::class,
+    ],
+  ],
+  links: [
+    'delete-form' => '/admin/people/roles/manage/{user_role}/delete',
+    'edit-form' => '/admin/people/roles/manage/{user_role}',
+    'edit-permissions-form' => '/admin/people/permissions/{user_role}',
+    'collection' => '/admin/people/roles',
+  ],
+  admin_permission: 'administer permissions',
+  label_count: [
+    'singular' => '@count role',
+    'plural' => '@count roles',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'weight',
+    'is_admin',
+    'permissions',
+  ],
+)]
 class Role extends ConfigEntityBase implements RoleInterface {
 
   /**
diff --git a/core/modules/user/src/Entity/User.php b/core/modules/user/src/Entity/User.php
index 84d384b0060f8250abab579b3ab6c0f779db935e..a487c4cc9332b6cd7518fd9ccb036c39479d342a 100644
--- a/core/modules/user/src/Entity/User.php
+++ b/core/modules/user/src/Entity/User.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\user\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
@@ -9,62 +11,70 @@
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\Flood\PrefixFloodInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\user\Form\UserCancelForm;
+use Drupal\user\ProfileForm;
+use Drupal\user\ProfileTranslationHandler;
+use Drupal\user\RegisterForm;
 use Drupal\user\RoleInterface;
 use Drupal\user\StatusItem;
 use Drupal\user\TimeZoneItem;
+use Drupal\user\UserAccessControlHandler;
 use Drupal\user\UserInterface;
+use Drupal\user\UserListBuilder;
+use Drupal\user\UserStorage;
+use Drupal\user\UserStorageSchema;
+use Drupal\user\UserViewsData;
 
 /**
  * Defines the user entity class.
  *
  * The base table name here is plural, despite Drupal table naming standards,
  * because "user" is a reserved word in many databases.
- *
- * @ContentEntityType(
- *   id = "user",
- *   label = @Translation("User"),
- *   label_collection = @Translation("Users"),
- *   label_singular = @Translation("user"),
- *   label_plural = @Translation("users"),
- *   label_count = @PluralTranslation(
- *     singular = "@count user",
- *     plural = "@count users",
- *   ),
- *   handlers = {
- *     "storage" = "Drupal\user\UserStorage",
- *     "storage_schema" = "Drupal\user\UserStorageSchema",
- *     "access" = "Drupal\user\UserAccessControlHandler",
- *     "list_builder" = "Drupal\user\UserListBuilder",
- *     "views_data" = "Drupal\user\UserViewsData",
- *     "route_provider" = {
- *       "html" = "Drupal\user\Entity\UserRouteProvider",
- *     },
- *     "form" = {
- *       "default" = "Drupal\user\ProfileForm",
- *       "cancel" = "Drupal\user\Form\UserCancelForm",
- *       "register" = "Drupal\user\RegisterForm"
- *     },
- *     "translation" = "Drupal\user\ProfileTranslationHandler"
- *   },
- *   admin_permission = "administer users",
- *   base_table = "users",
- *   data_table = "users_field_data",
- *   translatable = TRUE,
- *   entity_keys = {
- *     "id" = "uid",
- *     "langcode" = "langcode",
- *     "uuid" = "uuid"
- *   },
- *   links = {
- *     "canonical" = "/user/{user}",
- *     "edit-form" = "/user/{user}/edit",
- *     "cancel-form" = "/user/{user}/cancel",
- *     "collection" = "/admin/people",
- *   },
- *   field_ui_base_route = "entity.user.admin_form",
- *   common_reference_target = TRUE
- * )
  */
+#[ContentEntityType(
+  id: 'user',
+  label: new TranslatableMarkup('User'),
+  label_collection: new TranslatableMarkup('Users'),
+  label_singular: new TranslatableMarkup('user'),
+  label_plural: new TranslatableMarkup('users'),
+  entity_keys: [
+    'id' => 'uid',
+    'langcode' => 'langcode',
+    'uuid' => 'uuid',
+  ],
+  handlers: [
+    'storage' => UserStorage::class,
+    'storage_schema' => UserStorageSchema::class,
+    'access' => UserAccessControlHandler::class,
+    'list_builder' => UserListBuilder::class,
+    'views_data' => UserViewsData::class,
+    'route_provider' => [
+      'html' => UserRouteProvider::class,
+    ],
+    'form' => [
+      'default' => ProfileForm::class,
+      'cancel' => UserCancelForm::class,
+      'register' => RegisterForm::class,
+    ],
+    'translation' => ProfileTranslationHandler::class,
+  ],
+  links: [
+    'canonical' => '/user/{user}',
+    'edit-form' => '/user/{user}/edit',
+    'cancel-form' => '/user/{user}/cancel',
+    'collection' => '/admin/people',
+  ],
+  admin_permission: 'administer users',
+  base_table: 'users',
+  data_table: 'users_field_data',
+  translatable: TRUE,
+  label_count: [
+    'singular' => '@count user',
+    'plural' => '@count users',
+  ],
+  field_ui_base_route: 'entity.user.admin_form',
+  common_reference_target: TRUE,
+)]
 class User extends ContentEntityBase implements UserInterface {
 
   use EntityChangedTrait;
diff --git a/core/modules/views/src/Entity/View.php b/core/modules/views/src/Entity/View.php
index e3f9dbe92790ab7a64b1de4affed5b5186a1d482..b93be8c7e0bcc85d7dd0fb79bb102d0bac7b4ac0 100644
--- a/core/modules/views/src/Entity/View.php
+++ b/core/modules/views/src/Entity/View.php
@@ -2,6 +2,8 @@
 
 namespace Drupal\views\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
@@ -13,36 +15,34 @@
 
 /**
  * Defines a View configuration entity class.
- *
- * @ConfigEntityType(
- *   id = "view",
- *   label = @Translation("View", context = "View entity type"),
- *   label_collection = @Translation("Views", context = "View entity type"),
- *   label_singular = @Translation("view", context = "View entity type"),
- *   label_plural = @Translation("views", context = "View entity type"),
- *   label_count = @PluralTranslation(
- *     singular = "@count view",
- *     plural = "@count views",
- *     context = "View entity type",
- *   ),
- *   admin_permission = "administer views",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "status" = "status"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "module",
- *     "description",
- *     "tag",
- *     "base_table",
- *     "base_field",
- *     "display",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'view',
+  label: new TranslatableMarkup('View', ['context' => 'View entity type']),
+  label_collection: new TranslatableMarkup('Views', ['context' => 'View entity type']),
+  label_singular: new TranslatableMarkup('view', ['context' => 'View entity type']),
+  label_plural: new TranslatableMarkup('views', ['context' => 'View entity type']),
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'status' => 'status',
+  ],
+  admin_permission: 'administer views',
+  label_count: [
+    'singular' => '@count view',
+    'plural' => '@count views',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'module',
+    'description',
+    'tag',
+    'base_table',
+    'base_field',
+    'display',
+  ],
+)]
 class View extends ConfigEntityBase implements ViewEntityInterface {
 
   /**
diff --git a/core/modules/views/tests/modules/views_config_entity_test/src/Entity/ViewsConfigEntityTest.php b/core/modules/views/tests/modules/views_config_entity_test/src/Entity/ViewsConfigEntityTest.php
index 42f74a3ba58f14c14974d3bf142b0c4333b9db3a..fc2560359a754f1a5821963988959c4bbc4e01f4 100644
--- a/core/modules/views/tests/modules/views_config_entity_test/src/Entity/ViewsConfigEntityTest.php
+++ b/core/modules/views/tests/modules/views_config_entity_test/src/Entity/ViewsConfigEntityTest.php
@@ -4,29 +4,32 @@
 
 namespace Drupal\views_config_entity_test\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\EntityListBuilder;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\views_config_entity_test\ViewsConfigEntityTestViewsData;
 
 /**
  * Defines a configuration-based entity type used for testing Views data.
- *
- * @ConfigEntityType(
- *   id = "views_config_entity_test",
- *   label = @Translation("Test config entity type with Views data"),
- *   handlers = {
- *     "list_builder" = "Drupal\Core\Entity\EntityListBuilder",
- *     "views_data" = "Drupal\views_config_entity_test\ViewsConfigEntityTestViewsData"
- *   },
- *   admin_permission = "administer modules",
- *   config_prefix = "type",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "name"
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *   }
- * )
  */
+#[ConfigEntityType(
+  id: 'views_config_entity_test',
+  label: new TranslatableMarkup('Test config entity type with Views data'),
+  config_prefix: 'type',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'name',
+  ],
+  handlers: [
+    'list_builder' => EntityListBuilder::class,
+    'views_data' => ViewsConfigEntityTestViewsData::class,
+  ],
+  admin_permission: 'administer modules',
+  config_export: [
+    'id',
+    'label',
+  ],
+)]
 class ViewsConfigEntityTest extends ConfigEntityBase {
 }
diff --git a/core/modules/workflows/src/Entity/Workflow.php b/core/modules/workflows/src/Entity/Workflow.php
index bb10c0271aac7926b22a4d0f6ba5819e595efe7b..7ab9e20f77e4d90af140dd7cf3e19794f3bed6b3 100644
--- a/core/modules/workflows/src/Entity/Workflow.php
+++ b/core/modules/workflows/src/Entity/Workflow.php
@@ -2,67 +2,78 @@
 
 namespace Drupal\workflows\Entity;
 
+use Drupal\Core\Entity\Attribute\ConfigEntityType;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Config\Entity\ConfigEntityBase;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityWithPluginCollectionInterface;
 use Drupal\Core\Plugin\DefaultSingleLazyPluginCollection;
 use Drupal\workflows\Exception\RequiredStateMissingException;
+use Drupal\workflows\Form\WorkflowAddForm;
+use Drupal\workflows\Form\WorkflowDeleteForm;
+use Drupal\workflows\Form\WorkflowEditForm;
+use Drupal\workflows\Form\WorkflowStateAddForm;
+use Drupal\workflows\Form\WorkflowStateDeleteForm;
+use Drupal\workflows\Form\WorkflowStateEditForm;
+use Drupal\workflows\Form\WorkflowTransitionAddForm;
+use Drupal\workflows\Form\WorkflowTransitionDeleteForm;
+use Drupal\workflows\Form\WorkflowTransitionEditForm;
+use Drupal\workflows\WorkflowAccessControlHandler;
 use Drupal\workflows\WorkflowInterface;
+use Drupal\workflows\WorkflowListBuilder;
 
 /**
  * Defines the workflow entity.
- *
- * @ConfigEntityType(
- *   id = "workflow",
- *   label = @Translation("Workflow"),
- *   label_collection = @Translation("Workflows"),
- *   label_singular = @Translation("workflow"),
- *   label_plural = @Translation("workflows"),
- *   label_count = @PluralTranslation(
- *     singular = "@count workflow",
- *     plural = "@count workflows",
- *   ),
- *   handlers = {
- *     "access" = "Drupal\workflows\WorkflowAccessControlHandler",
- *     "list_builder" = "Drupal\workflows\WorkflowListBuilder",
- *     "form" = {
- *       "add" = "Drupal\workflows\Form\WorkflowAddForm",
- *       "edit" = "Drupal\workflows\Form\WorkflowEditForm",
- *       "delete" = "Drupal\workflows\Form\WorkflowDeleteForm",
- *       "add-state" = "Drupal\workflows\Form\WorkflowStateAddForm",
- *       "edit-state" = "Drupal\workflows\Form\WorkflowStateEditForm",
- *       "delete-state" = "Drupal\workflows\Form\WorkflowStateDeleteForm",
- *       "add-transition" = "Drupal\workflows\Form\WorkflowTransitionAddForm",
- *       "edit-transition" = "Drupal\workflows\Form\WorkflowTransitionEditForm",
- *       "delete-transition" = "Drupal\workflows\Form\WorkflowTransitionDeleteForm",
- *     },
- *     "route_provider" = {
- *       "html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
- *     },
- *   },
- *   config_prefix = "workflow",
- *   admin_permission = "administer workflows",
- *   entity_keys = {
- *     "id" = "id",
- *     "label" = "label",
- *     "uuid" = "uuid",
- *   },
- *   links = {
- *     "add-form" = "/admin/config/workflow/workflows/add",
- *     "edit-form" = "/admin/config/workflow/workflows/manage/{workflow}",
- *     "delete-form" = "/admin/config/workflow/workflows/manage/{workflow}/delete",
- *     "add-state-form" = "/admin/config/workflow/workflows/manage/{workflow}/add_state",
- *     "add-transition-form" = "/admin/config/workflow/workflows/manage/{workflow}/add_transition",
- *     "collection" = "/admin/config/workflow/workflows",
- *   },
- *   config_export = {
- *     "id",
- *     "label",
- *     "type",
- *     "type_settings",
- *   },
- * )
  */
+#[ConfigEntityType(
+  id: 'workflow',
+  label: new TranslatableMarkup('Workflow'),
+  label_collection: new TranslatableMarkup('Workflows'),
+  label_singular: new TranslatableMarkup('workflow'),
+  label_plural: new TranslatableMarkup('workflows'),
+  config_prefix: 'workflow',
+  entity_keys: [
+    'id' => 'id',
+    'label' => 'label',
+    'uuid' => 'uuid',
+  ],
+  handlers: [
+    'access' => WorkflowAccessControlHandler::class,
+    'list_builder' => WorkflowListBuilder::class,
+    'form' => [
+      'add' => WorkflowAddForm::class,
+      'edit' => WorkflowEditForm::class,
+      'delete' => WorkflowDeleteForm::class,
+      'add-state' => WorkflowStateAddForm::class,
+      'edit-state' => WorkflowStateEditForm::class,
+      'delete-state' => WorkflowStateDeleteForm::class,
+      'add-transition' => WorkflowTransitionAddForm::class,
+      'edit-transition' => WorkflowTransitionEditForm::class,
+      'delete-transition' => WorkflowTransitionDeleteForm::class,
+    ],
+    'route_provider' => ['html' => AdminHtmlRouteProvider::class],
+  ],
+  links: [
+    'add-form' => '/admin/config/workflow/workflows/add',
+    'edit-form' => '/admin/config/workflow/workflows/manage/{workflow}',
+    'delete-form' => '/admin/config/workflow/workflows/manage/{workflow}/delete',
+    'add-state-form' => '/admin/config/workflow/workflows/manage/{workflow}/add_state',
+    'add-transition-form' => '/admin/config/workflow/workflows/manage/{workflow}/add_transition',
+    'collection' => '/admin/config/workflow/workflows',
+  ],
+  admin_permission: 'administer workflows',
+  label_count: [
+    'singular' => '@count workflow',
+    'plural' => '@count workflows',
+  ],
+  config_export: [
+    'id',
+    'label',
+    'type',
+    'type_settings',
+  ],
+)]
 class Workflow extends ConfigEntityBase implements WorkflowInterface, EntityWithPluginCollectionInterface {
 
   /**
diff --git a/core/modules/workspaces/src/Entity/Workspace.php b/core/modules/workspaces/src/Entity/Workspace.php
index 1e16282ed1bb5b878c5a8cdb3b82187be57f4440..edf75c94f5603cfa25507550bfb697f7ee1ca7b7 100644
--- a/core/modules/workspaces/src/Entity/Workspace.php
+++ b/core/modules/workspaces/src/Entity/Workspace.php
@@ -2,69 +2,78 @@
 
 namespace Drupal\workspaces\Entity;
 
+use Drupal\Core\Entity\Attribute\ContentEntityType;
 use Drupal\Core\Entity\ContentEntityBase;
 use Drupal\Core\Entity\EntityChangedTrait;
 use Drupal\Core\Entity\EntityStorageInterface;
 use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Entity\Routing\AdminHtmlRouteProvider;
 use Drupal\Core\Field\BaseFieldDefinition;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\user\EntityOwnerTrait;
+use Drupal\views\EntityViewsData;
+use Drupal\workspaces\Entity\Handler\IgnoredWorkspaceHandler;
+use Drupal\workspaces\Form\WorkspaceActivateForm;
+use Drupal\workspaces\Form\WorkspaceDeleteForm;
+use Drupal\workspaces\Form\WorkspaceForm;
+use Drupal\workspaces\WorkspaceAccessControlHandler;
 use Drupal\workspaces\WorkspaceInterface;
+use Drupal\workspaces\WorkspaceListBuilder;
+use Drupal\workspaces\WorkspaceViewBuilder;
 
 /**
  * The workspace entity class.
- *
- * @ContentEntityType(
- *   id = "workspace",
- *   label = @Translation("Workspace"),
- *   label_collection = @Translation("Workspaces"),
- *   label_singular = @Translation("workspace"),
- *   label_plural = @Translation("workspaces"),
- *   label_count = @PluralTranslation(
- *     singular = "@count workspace",
- *     plural = "@count workspaces"
- *   ),
- *   handlers = {
- *     "list_builder" = "\Drupal\workspaces\WorkspaceListBuilder",
- *     "view_builder" = "Drupal\workspaces\WorkspaceViewBuilder",
- *     "access" = "Drupal\workspaces\WorkspaceAccessControlHandler",
- *     "views_data" = "Drupal\views\EntityViewsData",
- *     "route_provider" = {
- *       "html" = "\Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
- *     },
- *     "form" = {
- *       "default" = "\Drupal\workspaces\Form\WorkspaceForm",
- *       "add" = "\Drupal\workspaces\Form\WorkspaceForm",
- *       "edit" = "\Drupal\workspaces\Form\WorkspaceForm",
- *       "delete" = "\Drupal\workspaces\Form\WorkspaceDeleteForm",
- *       "activate" = "\Drupal\workspaces\Form\WorkspaceActivateForm",
- *     },
- *     "workspace" = "\Drupal\workspaces\Entity\Handler\IgnoredWorkspaceHandler",
- *   },
- *   admin_permission = "administer workspaces",
- *   base_table = "workspace",
- *   revision_table = "workspace_revision",
- *   data_table = "workspace_field_data",
- *   revision_data_table = "workspace_field_revision",
- *   field_ui_base_route = "entity.workspace.collection",
- *   entity_keys = {
- *     "id" = "id",
- *     "revision" = "revision_id",
- *     "uuid" = "uuid",
- *     "label" = "label",
- *     "uid" = "uid",
- *     "owner" = "uid",
- *   },
- *   links = {
- *     "canonical" = "/admin/config/workflow/workspaces/manage/{workspace}",
- *     "add-form" = "/admin/config/workflow/workspaces/add",
- *     "edit-form" = "/admin/config/workflow/workspaces/manage/{workspace}/edit",
- *     "delete-form" = "/admin/config/workflow/workspaces/manage/{workspace}/delete",
- *     "activate-form" = "/admin/config/workflow/workspaces/manage/{workspace}/activate",
- *     "collection" = "/admin/config/workflow/workspaces",
- *   },
- * )
  */
+#[ContentEntityType(
+  id: 'workspace',
+  label: new TranslatableMarkup('Workspace'),
+  label_collection: new TranslatableMarkup('Workspaces'),
+  label_singular: new TranslatableMarkup('workspace'),
+  label_plural: new TranslatableMarkup('workspaces'),
+  entity_keys: [
+    'id' => 'id',
+    'revision' => 'revision_id',
+    'uuid' => 'uuid',
+    'label' => 'label',
+    'uid' => 'uid',
+    'owner' => 'uid',
+  ],
+  handlers: [
+    'list_builder' => WorkspaceListBuilder::class,
+    'view_builder' => WorkspaceViewBuilder::class,
+    'access' => WorkspaceAccessControlHandler::class,
+    'views_data' => EntityViewsData::class,
+    'route_provider' => [
+      'html' => AdminHtmlRouteProvider::class,
+    ],
+    'form' => [
+      'default' => WorkspaceForm::class,
+      'add' => WorkspaceForm::class,
+      'edit' => WorkspaceForm::class,
+      'delete' => WorkspaceDeleteForm::class,
+      'activate' => WorkspaceActivateForm::class,
+    ],
+    'workspace' => IgnoredWorkspaceHandler::class,
+  ],
+  links: [
+    'canonical' => '/admin/config/workflow/workspaces/manage/{workspace}',
+    'add-form' => '/admin/config/workflow/workspaces/add',
+    'edit-form' => '/admin/config/workflow/workspaces/manage/{workspace}/edit',
+    'delete-form' => '/admin/config/workflow/workspaces/manage/{workspace}/delete',
+    'activate-form' => '/admin/config/workflow/workspaces/manage/{workspace}/activate',
+    'collection' => '/admin/config/workflow/workspaces',
+  ],
+  admin_permission: 'administer workspaces',
+  base_table: 'workspace',
+  data_table: 'workspace_field_data',
+  revision_table: 'workspace_revision',
+  revision_data_table: 'workspace_field_revision',
+  label_count: [
+    'singular' => '@count workspace',
+    'plural' => '@count workspaces',
+  ],
+  field_ui_base_route: 'entity.workspace.collection',
+)]
 class Workspace extends ContentEntityBase implements WorkspaceInterface {
 
   use EntityChangedTrait;