diff --git a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
index b68148e5461dcdc4c02346161c3990f169af599e..96477b9f476cc6230363a7980ba5d3ca96c95ccd 100644
--- a/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
+++ b/app/assets/javascripts/pages/admin/application_settings/general/components/signup_form.vue
@@ -43,7 +43,6 @@ export default {
     'settingsPath',
     'signupEnabled',
     'requireAdminApprovalAfterUserSignup',
-    'sendUserConfirmationEmail',
     'emailConfirmationSetting',
     'minimumPasswordLength',
     'minimumPasswordLengthMin',
@@ -68,7 +67,6 @@ export default {
       form: {
         signupEnabled: this.signupEnabled,
         requireAdminApproval: this.requireAdminApprovalAfterUserSignup,
-        sendConfirmationEmail: this.sendUserConfirmationEmail,
         emailConfirmationSetting: this.emailConfirmationSetting,
         minimumPasswordLength: this.minimumPasswordLength,
         minimumPasswordLengthMin: this.minimumPasswordLengthMin,
@@ -204,7 +202,6 @@ export default {
     buttonText: s__('ApplicationSettings|Save changes'),
     signupEnabledLabel: s__('ApplicationSettings|Sign-up enabled'),
     requireAdminApprovalLabel: s__('ApplicationSettings|Require admin approval for new sign-ups'),
-    sendConfirmationEmailLabel: s__('ApplicationSettings|Send confirmation email on sign-up'),
     emailConfirmationSettingsLabel: s__('ApplicationSettings|Email confirmation settings'),
     emailConfirmationSettingsOffLabel: s__('ApplicationSettings|Off'),
     emailConfirmationSettingsOffHelpText: s__(
@@ -284,13 +281,6 @@ export default {
         data-testid="require-admin-approval-checkbox"
       />
 
-      <signup-checkbox
-        v-model="form.sendConfirmationEmail"
-        class="gl-mb-5"
-        name="application_setting[send_user_confirmation_email]"
-        :label="$options.i18n.sendConfirmationEmailLabel"
-      />
-
       <gl-form-group :label="$options.i18n.emailConfirmationSettingsLabel">
         <gl-form-radio-group
           v-model="form.emailConfirmationSetting"
diff --git a/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js b/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js
index 0d5c55cb87b16cd81cfa8298000fe779976c0717..395d8a38bf70c5aaa209b1dec4887a14f37eec05 100644
--- a/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js
+++ b/app/assets/javascripts/pages/admin/application_settings/signup_restrictions.js
@@ -14,7 +14,6 @@ export default function initSignupRestrictions(elementSelector = '#js-signup-for
     booleanAttributes: [
       'signupEnabled',
       'requireAdminApprovalAfterUserSignup',
-      'sendUserConfirmationEmail',
       'domainDenylistEnabled',
       'denylistTypeRawSelected',
       'emailRestrictionsEnabled',
diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb
index 47c7fa7e477f1aedc1eebe628972a52d595d73e1..2b2ac26284834481e3bf3695c8e4d716fb45d308 100644
--- a/app/helpers/application_settings_helper.rb
+++ b/app/helpers/application_settings_helper.rb
@@ -320,7 +320,6 @@ def visible_attributes
       :require_two_factor_authentication,
       :restricted_visibility_levels,
       :rsa_key_restriction,
-      :send_user_confirmation_email,
       :session_expire_delay,
       :shared_runners_enabled,
       :shared_runners_text,
@@ -548,7 +547,6 @@ def signup_form_data
       settings_path: general_admin_application_settings_path(anchor: 'js-signup-settings'),
       signup_enabled: @application_setting[:signup_enabled].to_s,
       require_admin_approval_after_user_signup: @application_setting[:require_admin_approval_after_user_signup].to_s,
-      send_user_confirmation_email: @application_setting[:send_user_confirmation_email].to_s,
       email_confirmation_setting: @application_setting[:email_confirmation_setting].to_s,
       minimum_password_length: @application_setting[:minimum_password_length],
       minimum_password_length_min: ApplicationSetting::DEFAULT_MINIMUM_PASSWORD_LENGTH,
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index f468ed5cfef282d710678557daa131073fc8d71e..29b86c2ac06ebdb6fe54289312e5120e4fe4af78 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -11,6 +11,7 @@ class ApplicationSetting < ApplicationRecord
   ignore_columns %i[elasticsearch_shards elasticsearch_replicas], remove_with: '14.4', remove_after: '2021-09-22'
   ignore_columns %i[static_objects_external_storage_auth_token], remove_with: '14.9', remove_after: '2022-03-22'
   ignore_column :user_email_lookup_limit, remove_with: '15.0', remove_after: '2022-04-18'
+  ignore_column :send_user_confirmation_email, remove_with: '15.8', remove_after: '2022-12-18'
 
   INSTANCE_REVIEW_MIN_USERS = 50
   GRAFANA_URL_ERROR_MESSAGE = 'Please check your Grafana URL setting in ' \
@@ -20,7 +21,7 @@ class ApplicationSetting < ApplicationRecord
     'Admin Area > Settings > General > Kroki'
 
   enum whats_new_variant: { all_tiers: 0, current_tier: 1, disabled: 2 }, _prefix: true
-  enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }
+  enum email_confirmation_setting: { off: 0, soft: 1, hard: 2 }, _prefix: true
 
   add_authentication_token_field :runners_registration_token, encrypted: -> { Feature.enabled?(:application_settings_tokens_optional_encryption) ? :optional : :required }
   add_authentication_token_field :health_check_access_token
diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 74fad46f205987f5d7b9f7d1055d01b9456c74c7..41b3885c8fc71b74ee0953b0a5bf365af7446262 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -76,6 +76,7 @@ def defaults
         eks_account_id: nil,
         eks_integration_enabled: false,
         eks_secret_access_key: nil,
+        email_confirmation_setting: 'off',
         email_restrictions_enabled: false,
         email_restrictions: nil,
         external_pipeline_validation_service_timeout: nil,
@@ -146,7 +147,6 @@ def defaults
         require_two_factor_authentication: false,
         restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
         rsa_key_restriction: default_min_key_size(:rsa),
-        send_user_confirmation_email: false,
         session_expire_delay: Settings.gitlab['session_expire_delay'],
         shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
         shared_runners_text: nil,
diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb
index 8ef1b3e06135b129717a2abe97851263a4d3ae7f..064bf132d3daf1dcc0fa40adebb56b3d147feaf7 100644
--- a/app/services/users/build_service.rb
+++ b/app/services/users/build_service.rb
@@ -117,7 +117,7 @@ def assign_skip_confirmation_from_settings?
     end
 
     def skip_user_confirmation_email_from_setting
-      !Gitlab::CurrentSettings.send_user_confirmation_email
+      Gitlab::CurrentSettings.email_confirmation_setting_off?
     end
 
     def use_fallback_name?
diff --git a/db/migrate/20221122225925_set_email_confirmation_setting_before_removing_send_user_confirmation_email_column.rb b/db/migrate/20221122225925_set_email_confirmation_setting_before_removing_send_user_confirmation_email_column.rb
new file mode 100644
index 0000000000000000000000000000000000000000..f92704ac212d1cbce8cbe70b833f8c1919f44e01
--- /dev/null
+++ b/db/migrate/20221122225925_set_email_confirmation_setting_before_removing_send_user_confirmation_email_column.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+class SetEmailConfirmationSettingBeforeRemovingSendUserConfirmationEmailColumn < Gitlab::Database::Migration[2.0]
+  restrict_gitlab_migration gitlab_schema: :gitlab_main
+
+  class ApplicationSetting < MigrationRecord
+    self.table_name = 'application_settings'
+  end
+
+  def up
+    return unless ApplicationSetting.exists?
+    return unless ApplicationSetting.last.send_user_confirmation_email
+
+    ApplicationSetting.last.update(email_confirmation_setting: 2)
+  end
+
+  def down
+    return unless ApplicationSetting.exists?
+
+    ApplicationSetting.last.update(email_confirmation_setting: 0)
+  end
+end
diff --git a/db/schema_migrations/20221122225925 b/db/schema_migrations/20221122225925
new file mode 100644
index 0000000000000000000000000000000000000000..81da88065a214ca341fc986ac37fd9aa77ea5894
--- /dev/null
+++ b/db/schema_migrations/20221122225925
@@ -0,0 +1 @@
+223aa6d68c159847c8a50889a270c32b10c4efbf6c1445870f156896d0a34559
\ No newline at end of file
diff --git a/doc/api/settings.md b/doc/api/settings.md
index 9a4f079d8dfc565e151befc8b2fa32376387cd3b..7d55180db94a5d9b567faf2e5df7e2f8297d965d 100644
--- a/doc/api/settings.md
+++ b/doc/api/settings.md
@@ -342,6 +342,7 @@ listed in the descriptions of the relevant settings.
 | `elasticsearch_password` **(PREMIUM)**   | string           | no                                   | The password of your Elasticsearch instance. |
 | `email_additional_text` **(PREMIUM)**    | string           | no                                   | Additional text added to the bottom of every email for legal/auditing/compliance reasons. |
 | `email_author_in_body`                   | boolean          | no                                   | Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead. |
+| `email_confirmation_setting`             | string           | no                                   | Specifies whether users must confirm their email before sign in. Possible values are `off`, `soft`, and `hard`. |
 | `enabled_git_access_protocol`            | string           | no                                   | Enabled protocols for Git access. Allowed values are: `ssh`, `http`, and `nil` to allow both protocols. |
 | `enforce_namespace_storage_limit`        | boolean          | no                                   | Enabling this permits enforcement of namespace storage limits. |
 | `enforce_terms`                          | boolean          | no                                   | (**If enabled, requires:** `terms`) Enforce application ToS to all users. |
@@ -451,7 +452,6 @@ listed in the descriptions of the relevant settings.
 | `require_two_factor_authentication`      | boolean          | no                                   | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. |
 | `restricted_visibility_levels`           | array of strings | no                                   | Selected levels cannot be used by non-Administrator users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. |
 | `rsa_key_restriction`                    | integer          | no                                   | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. |
-| `send_user_confirmation_email`            | boolean          | no                                   | Send confirmation email on sign-up. |
 | `session_expire_delay`                   | integer          | no                                   | Session duration in minutes. GitLab restart is required to apply changes. |
 | `shared_runners_enabled`                 | boolean          | no                                   | (**If enabled, requires:** `shared_runners_text` and `shared_runners_minutes`) Enable shared runners for new projects. |
 | `shared_runners_minutes` **(PREMIUM)**   | integer          | required by: `shared_runners_enabled` | Set the maximum number of CI/CD minutes that a group can use on shared runners per month. |
diff --git a/doc/security/user_email_confirmation.md b/doc/security/user_email_confirmation.md
index ffc537c8f10a1d89544f877f9ff05467cabb5f92..c3f19c92f91471638269fe578d594b9d6d1a05df 100644
--- a/doc/security/user_email_confirmation.md
+++ b/doc/security/user_email_confirmation.md
@@ -13,7 +13,7 @@ they confirm their email address.
 
 1. On the top bar, select **Main menu > Admin**.
 1. On the left sidebar, select **Settings > General** (`/admin/application_settings/general`).
-1. Expand the **Sign-up restrictions** section and look for the **Send confirmation email on sign-up** option.
+1. Expand the **Sign-up restrictions** section and look for the **Email confirmation settings** options.
 
 ## Confirmation token expiry
 
diff --git a/doc/user/admin_area/settings/sign_up_restrictions.md b/doc/user/admin_area/settings/sign_up_restrictions.md
index a7de85b86dfac0967842f9e807a76f4a5601e06a..8aabe503065e7bdf935a8d4461f1ad430415750a 100644
--- a/doc/user/admin_area/settings/sign_up_restrictions.md
+++ b/doc/user/admin_area/settings/sign_up_restrictions.md
@@ -60,7 +60,7 @@ To enforce confirmation of the email address used for new sign ups:
 
 1. On the top bar, select **Main menu > Admin**.
 1. On the left sidebar, select **Settings > General**, and expand **Sign-up restrictions**.
-1. Select the **Send confirmation email on sign-up** checkbox, then select **Save changes**.
+1. Under **Email confirmation settings**, select **Hard**.
 
 ## User cap
 
diff --git a/ee/app/services/users/email_verification/send_custom_confirmation_instructions_service.rb b/ee/app/services/users/email_verification/send_custom_confirmation_instructions_service.rb
index 4ba04a9bf2b5e89677fc617379e63e3ea41c7bc8..711f3b47cad50b6d803b1619b2243901baff95f2 100644
--- a/ee/app/services/users/email_verification/send_custom_confirmation_instructions_service.rb
+++ b/ee/app/services/users/email_verification/send_custom_confirmation_instructions_service.rb
@@ -48,7 +48,7 @@ def enabled?
       def self.enabled?(email)
         return false if ::Feature.enabled?(:soft_email_confirmation)
         return false if ::Gitlab::CurrentSettings.require_admin_approval_after_user_signup
-        return false unless ::Gitlab::CurrentSettings.send_user_confirmation_email
+        return false if ::Gitlab::CurrentSettings.email_confirmation_setting_off?
 
         # Since we might not have a persisted user yet, we cannot scope the feature flag on the user,
         # but since we do have an email, use this wrapper that implements `flipper_id` for email addresses.
diff --git a/ee/spec/controllers/trial_registrations_controller_spec.rb b/ee/spec/controllers/trial_registrations_controller_spec.rb
index 79be44e36034949f4a76d5a72a9ecffa68acafcc..30e61c961bd44d54b1a80ff3c4c0954cb2dd25f1 100644
--- a/ee/spec/controllers/trial_registrations_controller_spec.rb
+++ b/ee/spec/controllers/trial_registrations_controller_spec.rb
@@ -89,7 +89,7 @@
     end
 
     before do
-      stub_application_setting(send_user_confirmation_email: true)
+      stub_application_setting_enum('email_confirmation_setting', 'hard')
     end
 
     subject(:post_create) { post :create, params: { user: user_params } }
diff --git a/ee/spec/features/registrations/email_confirmation_spec.rb b/ee/spec/features/registrations/email_confirmation_spec.rb
index cea417b279f893b2e7b1ffe6952b44ed4eaa6df3..3323fb31aeed301f2fd243d079fa2e3a7a0d7280 100644
--- a/ee/spec/features/registrations/email_confirmation_spec.rb
+++ b/ee/spec/features/registrations/email_confirmation_spec.rb
@@ -14,7 +14,7 @@
   where(identity_verification: [true, false],
         soft_email_confirmation: [true, false],
         require_admin_approval_after_user_signup: [true, false],
-        send_user_confirmation_email: [true, false])
+        email_confirmation_setting: %w[off soft hard])
 
   with_them do
     before do
@@ -24,7 +24,7 @@
       stub_feature_flags(identity_verification: identity_verification)
       stub_feature_flags(soft_email_confirmation: soft_email_confirmation)
       stub_application_setting(require_admin_approval_after_user_signup: require_admin_approval_after_user_signup)
-      stub_application_setting(send_user_confirmation_email: send_user_confirmation_email)
+      stub_application_setting_enum('email_confirmation_setting', email_confirmation_setting)
 
       sign_up
     end
@@ -32,7 +32,7 @@
     it 'confirms identity and signs in successfully', :aggregate_failures, :js, :enable_admin_mode do
       expect_required_approval_and_sign_in if require_admin_approval_after_user_signup
 
-      if send_user_confirmation_email
+      unless Gitlab::CurrentSettings.email_confirmation_setting_off?
         if soft_email_confirmation
           expect_successful_sign_in_and_confirmation_banner
           expect_successful_resend_instructions(from_banner: true)
@@ -124,7 +124,11 @@ def expect_required_approval_and_sign_in
 
     perform_enqueued_jobs { Users::ApproveService.new(admin).execute(user) }
 
-    should_email(user, times: send_user_confirmation_email ? 2 : 1) # welcome email and optional confirmation email
+    # This is temporary as `soft_email_confirmation` is being removed and conflicts with the new
+    # `email_confirmation_setting` enum which will encompass `soft_email_confirmation`
+    number_of_emails = email_confirmation_setting == 'off' ? 1 : 2
+
+    should_email(user, times: number_of_emails) # welcome email and optional confirmation email
 
     sign_in
   end
diff --git a/ee/spec/features/users/identity_verification_spec.rb b/ee/spec/features/users/identity_verification_spec.rb
index 2e4104e5f851a85f55fcf4dfc5c7cb02896e3294..8a5c6fb41be5685fbf5f9f0e7d9217cd4fbecb01 100644
--- a/ee/spec/features/users/identity_verification_spec.rb
+++ b/ee/spec/features/users/identity_verification_spec.rb
@@ -12,8 +12,8 @@
     let(:user) { User.find_by_username(new_user.username) }
 
     before do
+      stub_application_setting_enum('email_confirmation_setting', 'hard')
       stub_application_setting(require_admin_approval_after_user_signup: false)
-      stub_application_setting(send_user_confirmation_email: true)
       stub_feature_flags(identity_verification_credit_card: false)
       stub_feature_flags(soft_email_confirmation: false)
       stub_feature_flags(arkose_labs_signup_challenge: false)
diff --git a/ee/spec/requests/ee/registrations_controller_spec.rb b/ee/spec/requests/ee/registrations_controller_spec.rb
index ad49fc86a6583433c6726d0043dad35c9f59ddaa..c40ea511fc7fa5205f5bd341a9d8a7c1389c9eb0 100644
--- a/ee/spec/requests/ee/registrations_controller_spec.rb
+++ b/ee/spec/requests/ee/registrations_controller_spec.rb
@@ -95,8 +95,8 @@
 
     describe 'identity verification' do
       before do
+        stub_application_setting_enum('email_confirmation_setting', 'hard')
         stub_application_setting(require_admin_approval_after_user_signup: false)
-        stub_application_setting(send_user_confirmation_email: true)
         stub_feature_flags(soft_email_confirmation: false)
         stub_feature_flags(arkose_labs_signup_challenge: false)
       end
diff --git a/ee/spec/services/ee/users/authorized_build_service_spec.rb b/ee/spec/services/ee/users/authorized_build_service_spec.rb
index 150fca2dace44e712e6186a3a804a31aab59989e..513c50c6b28959fc1c558b060d77efbc833e63d9 100644
--- a/ee/spec/services/ee/users/authorized_build_service_spec.rb
+++ b/ee/spec/services/ee/users/authorized_build_service_spec.rb
@@ -52,9 +52,9 @@
         end
       end
 
-      context 'when user confirmation is enabled' do
+      context 'when email confirmation setting is set to `hard`' do
         before do
-          stub_application_setting(send_user_confirmation_email: true)
+          stub_application_setting_enum('email_confirmation_setting', 'hard')
         end
 
         it_behaves_like 'unsuccessful user domain matching'
diff --git a/ee/spec/services/users/email_verification/send_custom_confirmation_instructions_service_spec.rb b/ee/spec/services/users/email_verification/send_custom_confirmation_instructions_service_spec.rb
index 88050d692ad3ddcb4f74d6f624ea70e1359ae0be..2acce7d12994d61f7f3a43f6095bb15f34a277e9 100644
--- a/ee/spec/services/users/email_verification/send_custom_confirmation_instructions_service_spec.rb
+++ b/ee/spec/services/users/email_verification/send_custom_confirmation_instructions_service_spec.rb
@@ -104,23 +104,23 @@
 
   describe '#enabled?' do
     where(:identity_verification, :soft_email_confirmation,
-      :require_admin_approval_after_user_signup, :send_user_confirmation_email, :enabled?) do
-      true  | true  | true  | true  | false
-      true  | true  | true  | false | false
-      true  | true  | false | true  | false
-      true  | true  | false | false | false
-      true  | false | true  | true  | false
-      true  | false | true  | false | false
-      true  | false | false | true  | true
-      true  | false | false | false | false
-      false | true  | true  | true  | false
-      false | true  | true  | false | false
-      false | true  | false | true  | false
-      false | true  | false | false | false
-      false | false | true  | true  | false
-      false | false | true  | false | false
-      false | false | false | true  | false
-      false | false | false | false | false
+      :require_admin_approval_after_user_signup, :email_confirmation_setting, :enabled?) do
+      true  | true  | true  | 'hard' | false
+      true  | true  | true  | 'off'  | false
+      true  | true  | false | 'hard' | false
+      true  | true  | false | 'off'  | false
+      true  | false | true  | 'hard' | false
+      true  | false | true  | 'off'  | false
+      true  | false | false | 'hard' | true
+      true  | false | false | 'off'  | false
+      false | true  | true  | 'hard' | false
+      false | true  | true  | 'off'  | false
+      false | true  | false | 'hard' | false
+      false | true  | false | 'off'  | false
+      false | false | true  | 'hard' | false
+      false | false | true  | 'off'  | false
+      false | false | false | 'hard' | false
+      false | false | false | 'off'  | false
     end
 
     with_them do
@@ -128,7 +128,7 @@
         stub_feature_flags(identity_verification: identity_verification)
         stub_feature_flags(soft_email_confirmation: soft_email_confirmation)
         stub_application_setting(require_admin_approval_after_user_signup: require_admin_approval_after_user_signup)
-        stub_application_setting(send_user_confirmation_email: send_user_confirmation_email)
+        stub_application_setting_enum('email_confirmation_setting', email_confirmation_setting)
       end
 
       it 'returns the expected result' do
diff --git a/ee/spec/support/shared_contexts/saas_registration_settings_context.rb b/ee/spec/support/shared_contexts/saas_registration_settings_context.rb
index 953d8ef641a32c8f29e22795b4a6f3e64b1a0140..a2e29113bbe7436918c4c4bcbe61df66f5163401 100644
--- a/ee/spec/support/shared_contexts/saas_registration_settings_context.rb
+++ b/ee/spec/support/shared_contexts/saas_registration_settings_context.rb
@@ -12,12 +12,11 @@
   include SaasRegistrationHelpers
 
   before do
-    stub_application_setting(
-      # Saas doesn't require admin approval.
-      require_admin_approval_after_user_signup: false,
-      # SaaS always requires confirmation
-      send_user_confirmation_email: true
-    )
+    # Saas doesn't require admin approval.
+    stub_application_setting(require_admin_approval_after_user_signup: false)
+
+    # SaaS always requires confirmation
+    stub_application_setting_enum('email_confirmation_setting', 'hard')
 
     stub_feature_flags(
       # our focus isn't around arkose/signup challenges, so we'll omit those
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index 2a5cf5999cf8b93ba59ca59472de2c4ac75604f8..134247751c9b4b0095070462cfb2fcabf60118fd 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -66,6 +66,7 @@ def filter_attributes_using_license(attrs)
         requires :eks_secret_access_key, type: String, desc: 'Secret access key for the EKS integration IAM user'
       end
       optional :email_author_in_body, type: Boolean, desc: 'Some email servers do not support overriding the email sender name. Enable this option to include the name of the author of the issue, merge request or comment in the email body instead.'
+      optional :email_confirmation_setting, type: String, values: ApplicationSetting.email_confirmation_settings.keys, desc: "Email confirmation setting, possible values: `off`, `soft`, and `hard`"
       optional :enabled_git_access_protocol, type: String, values: %w[ssh http nil], desc: 'Allow only the selected protocols to be used for Git access.'
       optional :gitpod_enabled, type: Boolean, desc: 'Enable Gitpod'
       given gitpod_enabled: ->(val) { val } do
@@ -140,7 +141,6 @@ def filter_attributes_using_license(attrs)
         requires :two_factor_grace_period, type: Integer, desc: 'Amount of time (in hours) that users are allowed to skip forced configuration of two-factor authentication'
       end
       optional :restricted_visibility_levels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Selected levels cannot be used by non-admin users for groups, projects or snippets. If the public level is restricted, user profiles are only visible to logged in users.'
-      optional :send_user_confirmation_email, type: Boolean, desc: 'Send confirmation email on sign-up'
       optional :session_expire_delay, type: Integer, desc: 'Session duration in minutes. GitLab restart is required to apply changes.'
       optional :shared_runners_enabled, type: Boolean, desc: 'Enable shared runners for new projects'
       given shared_runners_enabled: ->(val) { val } do
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index fb20322327a09d8c55d29692f2f3074e99471333..2a92076e68fe91d762df6a24844c4cb4bbea56aa 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4852,9 +4852,6 @@ msgstr ""
 msgid "ApplicationSettings|Send a confirmation email during sign up. New users must confirm their email address before they can log in."
 msgstr ""
 
-msgid "ApplicationSettings|Send confirmation email on sign-up"
-msgstr ""
-
 msgid "ApplicationSettings|Sign-up enabled"
 msgstr ""
 
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index e0ed58f291e6b44d35b745f8c58d626ccabdafde..0770f34d9dee858bc8c5bf5423ba514a042ac9fe 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -75,9 +75,9 @@
         end
 
         context 'email confirmation' do
-          context 'when `send_user_confirmation_email` is true' do
+          context 'when `email_confirmation_setting` is set to `hard`' do
             before do
-              stub_application_setting(send_user_confirmation_email: true)
+              stub_application_setting_enum('email_confirmation_setting', 'hard')
             end
 
             it 'does not send a confirmation email' do
@@ -122,9 +122,9 @@
         end
 
         context 'email confirmation' do
-          context 'when `send_user_confirmation_email` is true' do
+          context 'when `email_confirmation_setting` is set to `hard`' do
             before do
-              stub_application_setting(send_user_confirmation_email: true)
+              stub_application_setting_enum('email_confirmation_setting', 'hard')
               stub_feature_flags(identity_verification: false)
             end
 
@@ -142,18 +142,18 @@
         stub_feature_flags(identity_verification: false)
       end
 
-      context 'when send_user_confirmation_email is false' do
+      context 'when `email_confirmation_setting` is set to `off`' do
         it 'signs the user in' do
-          stub_application_setting(send_user_confirmation_email: false)
+          stub_application_setting_enum('email_confirmation_setting', 'off')
 
           expect { subject }.not_to have_enqueued_mail(DeviseMailer, :confirmation_instructions)
           expect(controller.current_user).not_to be_nil
         end
       end
 
-      context 'when send_user_confirmation_email is true' do
+      context 'when `email_confirmation_setting` is set to `hard`' do
         before do
-          stub_application_setting(send_user_confirmation_email: true)
+          stub_application_setting_enum('email_confirmation_setting', 'hard')
         end
 
         context 'when soft email confirmation is not enabled' do
diff --git a/spec/features/invites_spec.rb b/spec/features/invites_spec.rb
index 1e71904356d371566adc881d7d36c5437b26385a..1091bea1ce32eb50e09ee111bf45026beed2741f 100644
--- a/spec/features/invites_spec.rb
+++ b/spec/features/invites_spec.rb
@@ -155,11 +155,10 @@ def fill_in_welcome_form
     let(:new_user) { build_stubbed(:user) }
     let(:invite_email) { new_user.email }
     let(:group_invite) { create(:group_member, :invited, group: group, invite_email: invite_email, created_by: owner) }
-    let(:send_email_confirmation) { true }
     let(:extra_params) { { invite_type: Emails::Members::INITIAL_INVITE } }
 
     before do
-      stub_application_setting(send_user_confirmation_email: send_email_confirmation)
+      stub_application_setting_enum('email_confirmation_setting', 'hard')
     end
 
     context 'when registering using invitation email' do
@@ -181,7 +180,9 @@ def fill_in_welcome_form
       end
 
       context 'email confirmation disabled' do
-        let(:send_email_confirmation) { false }
+        before do
+          stub_application_setting_enum('email_confirmation_setting', 'off')
+        end
 
         context 'the user signs up for an account with the invitation email address' do
           it 'redirects to the most recent membership activity page with all the projects/groups invitations automatically accepted' do
diff --git a/spec/features/users/login_spec.rb b/spec/features/users/login_spec.rb
index e6b9e77ce739d757c29bd92b66c4c9e5c19ba111..105e9f97989d7baaf8f7c94fd348f7eb4131a9ee 100644
--- a/spec/features/users/login_spec.rb
+++ b/spec/features/users/login_spec.rb
@@ -103,7 +103,7 @@
     let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
 
     before do
-      stub_application_setting(send_user_confirmation_email: true)
+      stub_application_setting_enum('email_confirmation_setting', 'hard')
       allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
       stub_feature_flags(identity_verification: false)
     end
@@ -953,7 +953,7 @@ def sign_in_using_saml!
     let(:alert_message) { "To continue, you need to select the link in the confirmation email we sent to verify your email address. If you didn't get our email, select Resend confirmation email" }
 
     before do
-      stub_application_setting(send_user_confirmation_email: true)
+      stub_application_setting_enum('email_confirmation_setting', 'hard')
       stub_feature_flags(soft_email_confirmation: true)
       stub_feature_flags(identity_verification: false)
       allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb
index 6171aa3a05829e3d5ae8336f2d250174cd0cedda..1057ae48c7d88a1c04ebd830d6f12248c16ad60b 100644
--- a/spec/features/users/signup_spec.rb
+++ b/spec/features/users/signup_spec.rb
@@ -197,7 +197,7 @@ def confirm_email
     context 'with no errors' do
       context 'when sending confirmation email' do
         before do
-          stub_application_setting(send_user_confirmation_email: true)
+          stub_application_setting_enum('email_confirmation_setting', 'hard')
         end
 
         context 'when soft email confirmation is not enabled' do
@@ -239,7 +239,7 @@ def confirm_email
 
       context "when not sending confirmation email" do
         before do
-          stub_application_setting(send_user_confirmation_email: false)
+          stub_application_setting_enum('email_confirmation_setting', 'off')
         end
 
         it 'creates the user account and goes to dashboard' do
diff --git a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
index e6718f62b912fa6652da356cc2657ff67d4571c0..f2a951bcc76a89e9046b7614f343921822ea888d 100644
--- a/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
+++ b/spec/frontend/admin/signup_restrictions/components/signup_form_spec.js
@@ -54,7 +54,6 @@ describe('Signup Form', () => {
       prop                                     | propValue                                       | elementSelector                                                             | formElementPassedDataType | formElementKey | expected
       ${'signupEnabled'}                       | ${mockData.signupEnabled}                       | ${'[name="application_setting[signup_enabled]"]'}                           | ${'prop'}                 | ${'value'}     | ${mockData.signupEnabled}
       ${'requireAdminApprovalAfterUserSignup'} | ${mockData.requireAdminApprovalAfterUserSignup} | ${'[name="application_setting[require_admin_approval_after_user_signup]"]'} | ${'prop'}                 | ${'value'}     | ${mockData.requireAdminApprovalAfterUserSignup}
-      ${'sendUserConfirmationEmail'}           | ${mockData.sendUserConfirmationEmail}           | ${'[name="application_setting[send_user_confirmation_email]"]'}             | ${'prop'}                 | ${'value'}     | ${mockData.sendUserConfirmationEmail}
       ${'newUserSignupsCap'}                   | ${mockData.newUserSignupsCap}                   | ${'[name="application_setting[new_user_signups_cap]"]'}                     | ${'attribute'}            | ${'value'}     | ${mockData.newUserSignupsCap}
       ${'minimumPasswordLength'}               | ${mockData.minimumPasswordLength}               | ${'[name="application_setting[minimum_password_length]"]'}                  | ${'attribute'}            | ${'value'}     | ${mockData.minimumPasswordLength}
       ${'minimumPasswordLengthMin'}            | ${mockData.minimumPasswordLengthMin}            | ${'[name="application_setting[minimum_password_length]"]'}                  | ${'attribute'}            | ${'min'}       | ${mockData.minimumPasswordLengthMin}
diff --git a/spec/frontend/admin/signup_restrictions/mock_data.js b/spec/frontend/admin/signup_restrictions/mock_data.js
index dd1ed317497482115d41bccd916b3b509202f711..ce5ec2248fe1849ccd364f4dee06a9bdad777572 100644
--- a/spec/frontend/admin/signup_restrictions/mock_data.js
+++ b/spec/frontend/admin/signup_restrictions/mock_data.js
@@ -3,7 +3,6 @@ export const rawMockData = {
   settingsPath: 'path/to/settings',
   signupEnabled: 'true',
   requireAdminApprovalAfterUserSignup: 'true',
-  sendUserConfirmationEmail: 'true',
   emailConfirmationSetting: 'hard',
   minimumPasswordLength: '8',
   minimumPasswordLengthMin: '3',
@@ -32,7 +31,6 @@ export const mockData = {
   settingsPath: 'path/to/settings',
   signupEnabled: true,
   requireAdminApprovalAfterUserSignup: true,
-  sendUserConfirmationEmail: true,
   emailConfirmationSetting: 'hard',
   minimumPasswordLength: '8',
   minimumPasswordLengthMin: '3',
diff --git a/spec/frontend/admin/signup_restrictions/utils_spec.js b/spec/frontend/admin/signup_restrictions/utils_spec.js
index f07e14430f90a830a6905780e7524c07d9af75de..e393b07baa94bf41b93ed8797804932c56fee0eb 100644
--- a/spec/frontend/admin/signup_restrictions/utils_spec.js
+++ b/spec/frontend/admin/signup_restrictions/utils_spec.js
@@ -10,7 +10,6 @@ describe('utils', () => {
           booleanAttributes: [
             'signupEnabled',
             'requireAdminApprovalAfterUserSignup',
-            'sendUserConfirmationEmail',
             'domainDenylistEnabled',
             'denylistTypeRawSelected',
             'emailRestrictionsEnabled',
diff --git a/spec/lib/gitlab/auth/ldap/user_spec.rb b/spec/lib/gitlab/auth/ldap/user_spec.rb
index b471a89b4915b74128290d37555f91a3a87d994e..5771b1cd609761ff5351072502df4b710df7a43c 100644
--- a/spec/lib/gitlab/auth/ldap/user_spec.rb
+++ b/spec/lib/gitlab/auth/ldap/user_spec.rb
@@ -133,7 +133,7 @@
 
     context 'when user confirmation email is enabled' do
       before do
-        stub_application_setting send_user_confirmation_email: true
+        stub_application_setting_enum('email_confirmation_setting', 'hard')
       end
 
       it 'creates and confirms the user anyway' do
diff --git a/spec/lib/gitlab/auth/o_auth/user_spec.rb b/spec/lib/gitlab/auth/o_auth/user_spec.rb
index 95a518afcf11230baaf2cc655096f691eb823fee..bb81621ec92ec7056fc665dfb6563ff1362900d1 100644
--- a/spec/lib/gitlab/auth/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/auth/o_auth/user_spec.rb
@@ -108,7 +108,7 @@ def stub_omniauth_config(messages)
 
       context 'when user confirmation email is enabled' do
         before do
-          stub_application_setting send_user_confirmation_email: true
+          stub_application_setting_enum('email_confirmation_setting', 'hard')
         end
 
         it 'creates and confirms the user anyway' do
diff --git a/spec/lib/gitlab/auth/saml/user_spec.rb b/spec/lib/gitlab/auth/saml/user_spec.rb
index 6c9598f920eda859a5991660ce3d61c0f1b5cb5e..a8a5d8ae5df00458107e90bce774bafdacb8f625 100644
--- a/spec/lib/gitlab/auth/saml/user_spec.rb
+++ b/spec/lib/gitlab/auth/saml/user_spec.rb
@@ -317,7 +317,7 @@
 
       context 'when user confirmation email is enabled' do
         before do
-          stub_application_setting send_user_confirmation_email: true
+          stub_application_setting_enum('email_confirmation_setting', 'hard')
         end
 
         it 'creates and confirms the user anyway' do
diff --git a/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb b/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b9e92cddfb843bb122d2356005cd5108c2745638
--- /dev/null
+++ b/spec/migrations/set_email_confirmation_setting_before_removing_send_user_confirmation_email_column_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require_migration!
+
+RSpec.describe SetEmailConfirmationSettingBeforeRemovingSendUserConfirmationEmailColumn do
+  let(:migration) { described_class.new }
+  let(:application_settings_table) { table(:application_settings) }
+
+  describe '#up' do
+    context "when 'send_user_confirmation_email' is set to 'true'" do
+      it "updates 'email_confirmation_setting' to '2' (hard)" do
+        application_settings_table.create!(send_user_confirmation_email: true, email_confirmation_setting: 0)
+
+        migration.up
+
+        expect(application_settings_table.last.email_confirmation_setting).to eq 2
+      end
+    end
+
+    context "when 'send_user_confirmation_email' is set to 'false'" do
+      it "updates 'email_confirmation_setting' to '0' (off)" do
+        application_settings_table.create!(send_user_confirmation_email: false, email_confirmation_setting: 0)
+
+        migration.up
+
+        expect(application_settings_table.last.email_confirmation_setting).to eq 0
+      end
+    end
+  end
+
+  describe '#down' do
+    it "updates 'email_confirmation_setting' to default value: '0' (off)" do
+      application_settings_table.create!(send_user_confirmation_email: true, email_confirmation_setting: 2)
+
+      migration.down
+
+      expect(application_settings_table.last.email_confirmation_setting).to eq 0
+    end
+  end
+end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index cef19816bba133490509fb0c5bffe0b631c5c629..41754c0b55545daa7d489526481a94ceb239f6e9 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1589,10 +1589,6 @@
     let(:expired_confirmation_sent_at) { Date.today - described_class.confirm_within - 7.days }
     let(:extant_confirmation_sent_at) { Date.today }
 
-    before do
-      allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true)
-    end
-
     let(:user) do
       create(:user, :unconfirmed, unconfirmed_email: 'test@gitlab.com').tap do |user|
         user.update!(confirmation_sent_at: confirmation_sent_at)
diff --git a/spec/services/users/registrations_build_service_spec.rb b/spec/services/users/registrations_build_service_spec.rb
index bc3718dbdb29124507d32b46f7a517f08db099b6..fa53a4cc60492b59607d7282f7b947fc0931b688 100644
--- a/spec/services/users/registrations_build_service_spec.rb
+++ b/spec/services/users/registrations_build_service_spec.rb
@@ -16,7 +16,7 @@
 
     context 'when automatic user confirmation is not enabled' do
       before do
-        stub_application_setting(send_user_confirmation_email: true)
+        stub_application_setting_enum('email_confirmation_setting', 'hard')
       end
 
       context 'when skip_confirmation is true' do
@@ -44,7 +44,7 @@
 
     context 'when automatic user confirmation is enabled' do
       before do
-        stub_application_setting(send_user_confirmation_email: false)
+        stub_application_setting_enum('email_confirmation_setting', 'off')
       end
 
       context 'when skip_confirmation is true' do
diff --git a/spec/support/helpers/stub_configuration.rb b/spec/support/helpers/stub_configuration.rb
index 24c768258a17ac844e30de6393d687549d5f9dc1..4ca8f26be9ebdf0c039d69f0abc7dbb0ee6fddf1 100644
--- a/spec/support/helpers/stub_configuration.rb
+++ b/spec/support/helpers/stub_configuration.rb
@@ -20,6 +20,17 @@ def stub_application_setting(messages)
     allow_any_instance_of(ApplicationSetting).to receive(:cached_html_up_to_date?).and_return(false)
   end
 
+  # For enums with `_prefix: true`, this allows us to stub the application setting properly
+  def stub_application_setting_enum(setting, value)
+    stub_application_setting(setting.to_sym => value)
+
+    ApplicationSetting.send(setting.pluralize.to_sym).each_key do |key|
+      stub_application_setting("#{setting}_#{key}".to_sym => key == value)
+    end
+
+    Gitlab::CurrentSettings.send(setting)
+  end
+
   def stub_not_protect_default_branch
     stub_application_setting(
       default_branch_protection: Gitlab::Access::PROTECTION_NONE)
diff --git a/spec/support/shared_examples/services/users/build_service_shared_examples.rb b/spec/support/shared_examples/services/users/build_service_shared_examples.rb
index 6a8695e178675e32e5e4c9d2f472eac56e8a203a..e448f2f874b2c8e5082025c99bf1b8465d06d059 100644
--- a/spec/support/shared_examples/services/users/build_service_shared_examples.rb
+++ b/spec/support/shared_examples/services/users/build_service_shared_examples.rb
@@ -84,9 +84,10 @@
     end
   end
 
-  context 'when "send_user_confirmation_email" application setting is true' do
+  context 'when "email_confirmation_setting" application setting is set to `hard`' do
     before do
-      stub_application_setting(send_user_confirmation_email: true, signup_enabled?: true)
+      stub_application_setting_enum('email_confirmation_setting', 'hard')
+      stub_application_setting(signup_enabled?: true)
     end
 
     it 'does not confirm the user' do
@@ -94,9 +95,10 @@
     end
   end
 
-  context 'when "send_user_confirmation_email" application setting is false' do
+  context 'when "email_confirmation_setting" application setting is set to `off`' do
     before do
-      stub_application_setting(send_user_confirmation_email: false, signup_enabled?: true)
+      stub_application_setting_enum('email_confirmation_setting', 'off')
+      stub_application_setting(signup_enabled?: true)
     end
 
     it 'confirms the user' do