diff --git a/core/modules/user/config/schema/user.schema.yml b/core/modules/user/config/schema/user.schema.yml
index 699d0ee6fc5d4bdb2f57699eed91fd5232047198..ac54b6986d7d9947df50a1e7011285941adc527f 100644
--- a/core/modules/user/config/schema/user.schema.yml
+++ b/core/modules/user/config/schema/user.schema.yml
@@ -154,10 +154,14 @@ user.role.*:
 action.configuration.user_add_role_action:
   type: mapping
   label: 'Configuration for the add role action'
+  constraints:
+    FullyValidatable: ~
   mapping:
     rid:
       type: string
       label: 'The ID of the role to add'
+      constraints:
+        RoleExists: ~
 
 action.configuration.user_block_user_action:
   type: action_configuration_default
@@ -170,10 +174,14 @@ action.configuration.user_cancel_user_action:
 action.configuration.user_remove_role_action:
   type: mapping
   label: 'Configuration for the remove role action'
+  constraints:
+    FullyValidatable: ~
   mapping:
     rid:
       type: string
       label: 'The ID of the role to remove'
+      constraints:
+        RoleExists: ~
 
 action.configuration.user_unblock_user_action:
   type: action_configuration_default
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php b/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php
new file mode 100644
index 0000000000000000000000000000000000000000..790cfc0f2ba726032821b3e3a5991cce8de26fb0
--- /dev/null
+++ b/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraint.php
@@ -0,0 +1,27 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\user\Plugin\Validation\Constraint;
+
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Core\Validation\Attribute\Constraint;
+use Symfony\Component\Validator\Constraint as SymfonyConstraint;
+
+/**
+ * Checks if a role exists.
+ */
+#[Constraint(
+  id: 'RoleExists',
+  label: new TranslatableMarkup('Role exists', [], ['context' => 'Validation'])
+)]
+class RoleExistsConstraint extends SymfonyConstraint {
+
+  /**
+   * The error message if validation fails.
+   *
+   * @var string
+   */
+  public $message = "The role with id '@rid' does not exist.";
+
+}
diff --git a/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraintValidator.php b/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraintValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..a2652f742fe0b717184dac3dda052e0952e31d05
--- /dev/null
+++ b/core/modules/user/src/Plugin/Validation/Constraint/RoleExistsConstraintValidator.php
@@ -0,0 +1,54 @@
+<?php
+
+declare(strict_types = 1);
+
+namespace Drupal\user\Plugin\Validation\Constraint;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Validator\Constraint;
+use Symfony\Component\Validator\ConstraintValidator;
+use Symfony\Component\Validator\Exception\UnexpectedTypeException;
+
+/**
+ * Validates that a role exists.
+ */
+class RoleExistsConstraintValidator extends ConstraintValidator implements ContainerInjectionInterface {
+
+  /**
+   * Create a new RoleExistsConstraintValidator instance.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
+   *   The entity type manager.
+   */
+  public function __construct(private readonly EntityTypeManagerInterface $entity_type_manager) {}
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container): static {
+    return new static(
+      $container->get(EntityTypeManagerInterface::class),
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate($value, Constraint $constraint): void {
+    assert($constraint instanceof RoleExistsConstraint);
+
+    if (!is_string($value)) {
+      throw new UnexpectedTypeException($value, 'string');
+    }
+
+    $roleStorage = $this->entity_type_manager->getStorage('user_role');
+    if (!$roleStorage->load($value)) {
+      $this->context->addViolation($constraint->message, [
+        '@rid' => $value,
+      ]);
+    }
+  }
+
+}
diff --git a/core/modules/user/tests/src/Kernel/Plugin/Validation/Constraint/RoleExistsConstraintValidatorTest.php b/core/modules/user/tests/src/Kernel/Plugin/Validation/Constraint/RoleExistsConstraintValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9baaa479eef6827194ff7aba7bf7ef963f8c8cf6
--- /dev/null
+++ b/core/modules/user/tests/src/Kernel/Plugin/Validation/Constraint/RoleExistsConstraintValidatorTest.php
@@ -0,0 +1,65 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\user\Kernel\Plugin\Validation\Constraint;
+
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\user\Entity\Role;
+use Symfony\Component\Validator\Exception\UnexpectedTypeException;
+
+/**
+ * @group user
+ * @group Validation
+ *
+ * @covers \Drupal\user\Plugin\Validation\Constraint\RoleExistsConstraint
+ * @covers \Drupal\user\Plugin\Validation\Constraint\RoleExistsConstraintValidator
+ */
+class RoleExistsConstraintValidatorTest extends KernelTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = ['system', 'user'];
+
+  /**
+   * Tests that the constraint validator will only work with strings.
+   */
+  public function testValueMustBeAString(): void {
+    $definition = DataDefinition::create('any')
+      ->addConstraint('RoleExists');
+
+    $this->expectException(UnexpectedTypeException::class);
+    $this->expectExceptionMessage('Expected argument of type "string", "int" given');
+    $this->container->get('typed_data_manager')
+      ->create($definition, 39)
+      ->validate();
+  }
+
+  /**
+   * Tests when the constraint's entityTypeId value is not valid.
+   */
+  public function testRoleExists(): void {
+    // Validation error when role does not exist.
+    $definition = DataDefinition::create('string')
+      ->addConstraint('RoleExists');
+
+    $violations = $this->container->get('typed_data_manager')
+      ->create($definition, 'test_role')
+      ->validate();
+    $this->assertEquals('The role with id \'test_role\' does not exist.', $violations->get(0)->getMessage());
+    $this->assertCount(1, $violations);
+
+    // Validation success when role exists.
+    Role::create(['id' => 'test_role', 'label' => 'Test role'])->save();
+    $definition = DataDefinition::create('string')
+      ->addConstraint('RoleExists');
+
+    $violations = $this->container->get('typed_data_manager')
+      ->create($definition, 'test_role')
+      ->validate();
+    $this->assertCount(0, $violations);
+  }
+
+}