diff --git a/core/modules/help/src/Plugin/Search/HelpSearch.php b/core/modules/help/src/Plugin/Search/HelpSearch.php
index e59d67549d9a0d5171b57fb62c964c04cc1b2fa5..3d04ee86357ebcba67eaf8718a51a0b71a46e107 100644
--- a/core/modules/help/src/Plugin/Search/HelpSearch.php
+++ b/core/modules/help/src/Plugin/Search/HelpSearch.php
@@ -13,8 +13,10 @@
 use Drupal\Core\Messenger\MessengerInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\State\StateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\help\HelpSectionManager;
 use Drupal\help\SearchableHelpInterface;
+use Drupal\search\Attribute\Search;
 use Drupal\search\Plugin\SearchIndexingInterface;
 use Drupal\search\Plugin\SearchPluginBase;
 use Drupal\search\SearchIndexInterface;
@@ -30,15 +32,14 @@
  * @see \Drupal\help\HelpSearchInterface
  * @see \Drupal\help\HelpSectionPluginInterface
  *
- * @SearchPlugin(
- *   id = "help_search",
- *   title = @Translation("Help"),
- *   use_admin_theme = TRUE,
- * )
- *
  * @internal
  *   Plugin classes are internal.
  */
+#[Search(
+  id: 'help_search',
+  title: new TranslatableMarkup('Help'),
+  use_admin_theme: TRUE,
+)]
 class HelpSearch extends SearchPluginBase implements AccessibleInterface, SearchIndexingInterface {
 
   /**
diff --git a/core/modules/node/src/Plugin/Search/NodeSearch.php b/core/modules/node/src/Plugin/Search/NodeSearch.php
index 88be72514009e3a7d9d44a04d5c93a8ae0614427..734381a2a777fa057b8907273f2778c89eb9e4ff 100644
--- a/core/modules/node/src/Plugin/Search/NodeSearch.php
+++ b/core/modules/node/src/Plugin/Search/NodeSearch.php
@@ -19,7 +19,9 @@
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Security\TrustedCallbackInterface;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\node\NodeInterface;
+use Drupal\search\Attribute\Search;
 use Drupal\search\Plugin\ConfigurableSearchPluginBase;
 use Drupal\search\Plugin\SearchIndexingInterface;
 use Drupal\search\SearchIndexInterface;
@@ -28,12 +30,11 @@
 
 /**
  * Handles searching for node entities using the Search module index.
- *
- * @SearchPlugin(
- *   id = "node_search",
- *   title = @Translation("Content")
- * )
  */
+#[Search(
+  id: 'node_search',
+  title: new TranslatableMarkup('Content'),
+)]
 class NodeSearch extends ConfigurableSearchPluginBase implements AccessibleInterface, SearchIndexingInterface, TrustedCallbackInterface {
 
   /**
diff --git a/core/modules/search/src/Attribute/Search.php b/core/modules/search/src/Attribute/Search.php
new file mode 100644
index 0000000000000000000000000000000000000000..efe805c76be92c3b622ef874fa366e8f82d124a6
--- /dev/null
+++ b/core/modules/search/src/Attribute/Search.php
@@ -0,0 +1,40 @@
+<?php
+
+namespace Drupal\search\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Defines a Search type attribute for plugin discovery.
+ *
+ * Search classes define search types for the core Search module. Each search
+ * type can be used to create search pages from the Search settings page.
+ *
+ * @see SearchPluginBase
+ *
+ * @ingroup search
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+class Search extends Plugin {
+
+  /**
+   * Constructs a Search attribute.
+   *
+   * @param string $id
+   *   The plugin ID.
+   * @param \Drupal\Core\StringTranslation\TranslatableMarkup|null $title
+   *   The title for the search page tab.
+   * @param bool $use_admin_theme
+   *   Whether search results should be displayed in admin theme or not.
+   * @param class-string|null $deriver
+   *   (optional) The deriver class.
+   */
+  public function __construct(
+    public readonly string $id,
+    public readonly ?TranslatableMarkup $title = NULL,
+    public readonly bool $use_admin_theme = FALSE,
+    public readonly ?string $deriver = NULL
+  ) {}
+
+}
diff --git a/core/modules/search/src/SearchPluginManager.php b/core/modules/search/src/SearchPluginManager.php
index caea2baebbf84b2cde6814729ec10c300105c34a..6de81aec2e781c44c984123d60259a35331fe711 100644
--- a/core/modules/search/src/SearchPluginManager.php
+++ b/core/modules/search/src/SearchPluginManager.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\search\Attribute\Search;
 
 /**
  * SearchExecute plugin manager.
@@ -23,7 +24,7 @@ class SearchPluginManager extends DefaultPluginManager {
    *   The module handler to invoke the alter hook with.
    */
   public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
-    parent::__construct('Plugin/Search', $namespaces, $module_handler, 'Drupal\search\Plugin\SearchInterface', 'Drupal\search\Annotation\SearchPlugin');
+    parent::__construct('Plugin/Search', $namespaces, $module_handler, 'Drupal\search\Plugin\SearchInterface', Search::class, 'Drupal\search\Annotation\SearchPlugin');
     $this->setCacheBackend($cache_backend, 'search_plugins');
     $this->alterInfo('search_plugin');
   }
diff --git a/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php b/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php
index 5726e247f656bf0b1b2da79a7a0b4f583821da9a..c13643f3a08a752ba6b140da03e8e9865061a7c5 100644
--- a/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php
+++ b/core/modules/search/tests/modules/search_extra_type/src/Plugin/Search/SearchExtraTypeSearch.php
@@ -4,18 +4,19 @@
 
 use Drupal\Component\Render\FormattableMarkup;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
 use Drupal\Core\Url;
+use Drupal\search\Attribute\Search;
 use Drupal\search\Plugin\ConfigurableSearchPluginBase;
 
 /**
  * Executes a dummy keyword search.
- *
- * @SearchPlugin(
- *   id = "search_extra_type_search",
- *   title = @Translation("Dummy search type"),
- *   use_admin_theme = TRUE,
- * )
  */
+#[Search(
+  id: 'search_extra_type_search',
+  title: new TranslatableMarkup('Dummy search type'),
+  use_admin_theme: TRUE,
+)]
 class SearchExtraTypeSearch extends ConfigurableSearchPluginBase {
 
   /**
diff --git a/core/modules/user/src/Plugin/Search/UserSearch.php b/core/modules/user/src/Plugin/Search/UserSearch.php
index 28f5d0e833638eea605f13f4bc349ee54d9c0273..c5d99b156a5cf10040e1f00489e6d6ba3488a27e 100644
--- a/core/modules/user/src/Plugin/Search/UserSearch.php
+++ b/core/modules/user/src/Plugin/Search/UserSearch.php
@@ -9,17 +9,18 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Access\AccessibleInterface;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\search\Attribute\Search;
 use Drupal\search\Plugin\SearchPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Executes a keyword search for users against the {users} database table.
- *
- * @SearchPlugin(
- *   id = "user_search",
- *   title = @Translation("Users")
- * )
  */
+#[Search(
+  id: 'user_search',
+  title: new TranslatableMarkup('Users'),
+)]
 class UserSearch extends SearchPluginBase implements AccessibleInterface {
 
   /**