diff --git a/CRM/Core/Payment/Stripe.php b/CRM/Core/Payment/Stripe.php
index 667529bf4d9cebcd50ff4af79dd7e3a05418652f..6a964f31dc8fd8a9bb420c53360880a1ee837f6c 100644
--- a/CRM/Core/Payment/Stripe.php
+++ b/CRM/Core/Payment/Stripe.php
@@ -945,24 +945,54 @@ class CRM_Core_Payment_Stripe extends CRM_Core_Payment {
     # See https://stripe.com/docs/statement-descriptors
     $disallowed_characters = ['<', '>', '\\', "'", '"', '*'];
 
-    if (!isset(\Civi::$statics[__CLASS__]['description']['contact_contribution'])) {
-      \Civi::$statics[__CLASS__]['description']['contact_contribution'] = $params['contactID'] . '-' . ($params['contributionID'] ?? 'XX');
-    }
+    $contactContributionID = $params['contactID'] . '-' . ($params['contributionID'] ?? 'XX');
     switch ($type) {
+      // For statement_descriptor / statement_descriptor_suffix:
+      // 1. Get it from the setting if defined.
+      // 2. Generate it from the contact/contribution ID + description (event/contribution title).
+      // 3. Set it to the current "domain" name in CiviCRM.
+      // 4. If we end up with a blank descriptor Stripe will reject it - https://lab.civicrm.org/extensions/stripe/-/issues/293
+      //   so we set it to ".".
       case 'statement_descriptor':
-        $description = substr(\Civi::$statics[__CLASS__]['description']['contact_contribution'] . " " . $params['description'], 0, 22);
-        break;
+        $description = \Civi::settings()->get('stripe_statementdescriptor');
+        if (empty($description)) {
+          $description = trim("{$contactContributionID} {$params['description']}");
+          if (empty($description)) {
+            $description = \Civi\Api4\Domain::get(FALSE)
+              ->setCurrentDomain(TRUE)
+              ->addSelect('name')
+              ->execute()
+              ->first()['name'];
+          }
+        }
+        $description = str_replace($disallowed_characters, '', $description);
+        if (empty($description)) {
+          $description = '.';
+        }
+        return substr($description, 0, 22);
 
       case 'statement_descriptor_suffix':
-        $description = \Civi::$statics[__CLASS__]['description']['contact_contribution'] . " " . substr($params['description'],0,7);
-        break;
+        $description = \Civi::settings()->get('stripe_statementdescriptorsuffix');
+        if (empty($description)) {
+          $description = trim("{$contactContributionID} {$params['description']}");
+          if (empty($description)) {
+            $description = \Civi\Api4\Domain::get(FALSE)
+              ->setCurrentDomain(TRUE)
+              ->addSelect('name')
+              ->execute()
+              ->first()['name'];
+          }
+        }
+        $description = str_replace($disallowed_characters, '', $description);
+        if (empty($description)) {
+          $description = '.';
+        }
+        return substr($description,0,12);
 
       default:
         // The (paymentIntent) full description has no restriction on characters that are allowed/disallowed.
-        return "{$params['description']} " . \Civi::$statics[__CLASS__]['description']['contact_contribution'] . " #" . CRM_Utils_Array::value('invoiceID', $params);
+        return "{$params['description']} " . $contactContributionID . " #" . ($params['invoiceID'] ?? '');
     }
-
-    return str_replace($disallowed_characters, ' ', $description);
   }
 
   /**
diff --git a/docs/images/settings_statementdescriptor.png b/docs/images/settings_statementdescriptor.png
new file mode 100644
index 0000000000000000000000000000000000000000..174212ac75f632b7fcdc232cdaa4566b5305f2ac
Binary files /dev/null and b/docs/images/settings_statementdescriptor.png differ
diff --git a/settings/stripe.setting.php b/settings/stripe.setting.php
index 0714dc9dfbe2b4501fb78716d0dd7a9b73358b11..41ff491d671f3ccf2d4b992561c7796326426128 100644
--- a/settings/stripe.setting.php
+++ b/settings/stripe.setting.php
@@ -141,4 +141,55 @@ Required by the paymentRequest button. 2-character code (eg. "US") that can be f
       ],
     ],
   ],
+  'stripe_statementdescriptor' => [
+    'name' => 'stripe_statementdescriptor',
+    'type' => 'String',
+    'html_type' => 'text',
+    'default' => '',
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'title' => E::ts('Statement Descriptor'),
+    'description' => E::ts('The text that will be shown on the customer bank/card statement.
+If this is empty it will be generated by CiviCRM using the information available (Contact/ContributionID + event/contribution title).
+<br/>If you want to use a fixed descriptor specify one here - make sure you comply with the <a href="%1" target="_blank">Statement descriptor requirements</a>.
+<br/>Max length 22 characters.',
+      [
+        1 => 'https://stripe.com/docs/statement-descriptors',
+      ]),
+    'html_attributes' => [
+      'size' => 30,
+      'maxlength' => 22,
+    ],
+    'settings_pages' => [
+      'stripe' => [
+        'weight' => 50,
+      ]
+    ],
+  ],
+  'stripe_statementdescriptorsuffix' => [
+    'name' => 'stripe_statementdescriptorsuffix',
+    'type' => 'String',
+    'html_type' => 'text',
+    'default' => '',
+    'is_domain' => 1,
+    'is_contact' => 0,
+    'title' => E::ts('Statement descriptor Suffix (Cards only)'),
+    'description' => E::ts('For credit cards you can specify a static <a href="%2" target="_blank">"prefix"</a> in the Stripe account dashboard.
+If this is empty the "suffix" will be generated by CiviCRM using the information available (Contact/ContributionID + event/contribution title).
+<br/>If you want to use a fixed descriptor specify the suffix here - make sure you comply with the <a href="%1" target="_blank">Statement descriptor requirements</a>.
+<br/>Max length 12 characters',
+      [
+        1 => 'https://stripe.com/docs/statement-descriptors',
+        2 => 'https://stripe.com/docs/statement-descriptors#static',
+      ]),
+    'html_attributes' => [
+      'size' => 20,
+      'maxlength' => 12,
+    ],
+    'settings_pages' => [
+      'stripe' => [
+        'weight' => 60,
+      ]
+    ],
+  ],
 ];