diff --git a/lib/gitlab/database/background_migration/batched_background_migration_dictionary.rb b/lib/gitlab/database/background_migration/batched_background_migration_dictionary.rb
deleted file mode 100644
index a6efa09afdaae674b952fe071b3685af44bfbd77..0000000000000000000000000000000000000000
--- a/lib/gitlab/database/background_migration/batched_background_migration_dictionary.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-# frozen_string_literal: true
-
-module Gitlab
-  module Database
-    module BackgroundMigration
-      class BatchedBackgroundMigrationDictionary
-        def self.entry(migration_job_name)
-          entries_by_migration_job_name[migration_job_name]
-        end
-
-        private_class_method def self.entries_by_migration_job_name
-          @entries_by_migration_job_name ||= Dir.glob(dict_path).to_h do |file_path|
-            entry = Entry.new(file_path)
-            [entry.migration_job_name, entry]
-          end
-        end
-
-        private_class_method def self.dict_path
-          Rails.root.join('db/docs/batched_background_migrations/*.yml')
-        end
-
-        class Entry
-          def initialize(file_path)
-            @file_path = file_path
-            @data = YAML.load_file(file_path)
-          end
-
-          def migration_job_name
-            data['migration_job_name']
-          end
-
-          def finalized_by
-            data['finalized_by']
-          end
-
-          private
-
-          attr_reader :file_path, :data
-        end
-      end
-    end
-  end
-end
diff --git a/lib/gitlab/database/migrations/batched_background_migration_helpers.rb b/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
index 32b02422903834c37b64fab48f862c63e1d0c8d3..970e20279c964e0d94247654d581326022dcaa27 100644
--- a/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
+++ b/lib/gitlab/database/migrations/batched_background_migration_helpers.rb
@@ -19,6 +19,14 @@ module BatchedBackgroundMigrationHelpers
         BATCH_MIN_VALUE = 1 # Default minimum value for batched migrations
         BATCH_MIN_DELAY = 2.minutes.freeze # Minimum delay between batched migrations
 
+        ENFORCE_EARLY_FINALIZATION_FROM_VERSION = '20240905124117'
+        EARLY_FINALIZATION_ERROR = <<-MESSAGE.squeeze(' ').strip
+          Batched migration should be finalized only after at-least one required stop from queuing it.
+          This is to ensure that we are not breaking the upgrades for self-managed instances.
+
+          For more info visit: https://docs.gitlab.com/ee/development/database/batched_background_migrations.html#finalize-a-batched-background-migration
+        MESSAGE
+
         # Creates a batched background migration for the given table. A batched migration runs one job
         # at a time, computing the bounds of the next batch based on the current migration settings and the previous
         # batch bounds. Each job's execution status is tracked in the database as the migration runs. The given job
@@ -188,7 +196,14 @@ def gitlab_schema_from_context
           end
         end
 
-        def ensure_batched_background_migration_is_finished(job_class_name:, table_name:, column_name:, job_arguments:, finalize: true)
+        def ensure_batched_background_migration_is_finished(
+          job_class_name:,
+          table_name:,
+          column_name:,
+          job_arguments:,
+          finalize: true,
+          skip_early_finalization_validation: false
+        )
           Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas.require_dml_mode!
 
           if transaction_open?
@@ -216,6 +231,10 @@ def ensure_batched_background_migration_is_finished(job_class_name:, table_name:
 
           return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
 
+          if migration.respond_to?(:queued_migration_version) && !skip_early_finalization_validation
+            prevent_early_finalization!(migration.queued_migration_version, version)
+          end
+
           return if migration.finalized?
 
           if migration.finished?
@@ -269,6 +288,21 @@ def assign_attributes_safely(migration, max_batch_size, batch_table_name, gitlab
           end
           # rubocop:enable GitlabSecurity/PublicSend
         end
+
+        def prevent_early_finalization!(queued_migration_version, version)
+          return if version.to_s <= ENFORCE_EARLY_FINALIZATION_FROM_VERSION || queued_migration_version.blank?
+
+          queued_migration_milestone = Gitlab::Utils::BatchedBackgroundMigrationsDictionary
+                                         .new(queued_migration_version)
+                                         .milestone
+
+          return unless queued_migration_milestone.present?
+
+          queued_migration_milestone = Gitlab::VersionInfo.parse_from_milestone(queued_migration_milestone)
+          last_required_stop = Gitlab::Database.upgrade_path.last_required_stop
+
+          raise EARLY_FINALIZATION_ERROR unless queued_migration_milestone <= last_required_stop
+        end
       end
     end
   end
diff --git a/lib/gitlab/utils/batched_background_migrations_dictionary.rb b/lib/gitlab/utils/batched_background_migrations_dictionary.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8dd903e79af9e49b33aade8bd5ffc45adc686952
--- /dev/null
+++ b/lib/gitlab/utils/batched_background_migrations_dictionary.rb
@@ -0,0 +1,74 @@
+# frozen_string_literal: true
+
+module Gitlab
+  module Utils
+    class BatchedBackgroundMigrationsDictionary
+      DICTIONARY_BASE_DIR = 'db/docs/batched_background_migrations'
+
+      attr_reader :queued_migration_version
+
+      class << self
+        def entries
+          return @entries if @entries.present? && !Rails.env.test?
+
+          @entries = Dir.glob("*.yml", base: DICTIONARY_BASE_DIR).each_with_object({}) do |file_name, data|
+            dictionary = YAML.load_file(File.join(DICTIONARY_BASE_DIR, file_name))
+
+            next unless dictionary['queued_migration_version'].present?
+
+            data[dictionary['queued_migration_version'].to_s] = {
+              migration_job_name: dictionary['migration_job_name'],
+              introduced_by_url: dictionary['introduced_by_url'],
+              finalized_by: dictionary['finalized_by'].to_s,
+              milestone: dictionary['milestone']
+            }
+
+            data[dictionary['migration_job_name']] = data[dictionary['queued_migration_version'].to_s].merge(
+              queued_migration_version: dictionary['queued_migration_version']
+            )
+          end
+        end
+
+        def entry(migration_job_name)
+          return unless entries&.dig(migration_job_name)
+
+          new(entries[migration_job_name][:queued_migration_version])
+        end
+
+        # Used by BackgroundMigration/DictionaryFile cop to invalidate its cache
+        # if the contents of `db/docs/batched_background_migrations` changes.
+        def checksum(skip_memoization: false)
+          return @checksum if @checksum.present? && !skip_memoization
+
+          @checksum = Digest::SHA256.hexdigest(entries.to_s)
+        end
+      end
+
+      def initialize(queued_migration_version)
+        @queued_migration_version = queued_migration_version
+      end
+
+      def finalized_by
+        entry&.dig(:finalized_by)
+      end
+
+      def introduced_by_url
+        entry&.dig(:introduced_by_url)
+      end
+
+      def milestone
+        entry&.dig(:milestone)
+      end
+
+      def migration_job_name
+        entry&.dig(:migration_job_name)
+      end
+
+      private
+
+      def entry
+        @entry ||= self.class.entries[queued_migration_version.to_s]
+      end
+    end
+  end
+end
diff --git a/rubocop/batched_background_migrations_dictionary.rb b/rubocop/batched_background_migrations_dictionary.rb
deleted file mode 100644
index 4778a382112c0e6aef53ce21bc933076ca482fcd..0000000000000000000000000000000000000000
--- a/rubocop/batched_background_migrations_dictionary.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-# frozen_string_literal: true
-
-module RuboCop
-  class BatchedBackgroundMigrationsDictionary
-    DICTIONARY_BASE_DIR = 'db/docs/batched_background_migrations'
-
-    attr_reader :queued_migration_version
-
-    class << self
-      def dictionary_data
-        @dictionary_data ||= Dir.glob("*.yml", base: DICTIONARY_BASE_DIR).each_with_object({}) do |file_name, data|
-          dictionary = YAML.load_file(File.join(DICTIONARY_BASE_DIR, file_name))
-
-          next unless dictionary['queued_migration_version'].present?
-
-          data[dictionary['queued_migration_version'].to_s] = {
-            introduced_by_url: dictionary['introduced_by_url'],
-            finalized_by: dictionary['finalized_by'].to_s,
-            milestone: dictionary['milestone']
-          }
-        end
-      end
-
-      def checksum
-        @checksum ||= Digest::SHA256.hexdigest(dictionary_data.to_s)
-      end
-    end
-
-    def initialize(queued_migration_version)
-      @queued_migration_version = queued_migration_version
-    end
-
-    def finalized_by
-      dictionary_data&.dig(:finalized_by)
-    end
-
-    def introduced_by_url
-      dictionary_data&.dig(:introduced_by_url)
-    end
-
-    def milestone
-      dictionary_data&.dig(:milestone)
-    end
-
-    private
-
-    def dictionary_data
-      @dictionary_data ||= self.class.dictionary_data[queued_migration_version.to_s]
-    end
-  end
-end
diff --git a/rubocop/cop/background_migration/dictionary_file.rb b/rubocop/cop/background_migration/dictionary_file.rb
index d0c02c7c488275fe3cf7775c905462e54a1661f5..a7b4726e64357be7e174704f86b24b94b29bdb0e 100644
--- a/rubocop/cop/background_migration/dictionary_file.rb
+++ b/rubocop/cop/background_migration/dictionary_file.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 require_relative '../../migration_helpers'
-require_relative '../../batched_background_migrations_dictionary'
+require_relative '../../../lib/gitlab/utils/batched_background_migrations_dictionary'
 
 URL_PATTERN = %r{\Ahttps://gitlab\.com/gitlab-org/gitlab/-/merge_requests/\d+\z}
 
@@ -52,7 +52,7 @@ def on_class(node)
         end
 
         def external_dependency_checksum
-          RuboCop::BatchedBackgroundMigrationsDictionary.checksum
+          ::Gitlab::Utils::BatchedBackgroundMigrationsDictionary.checksum
         end
 
         private
@@ -78,7 +78,7 @@ def validate_dictionary_file(migration_name, node)
             return [:missing_dictionary, { file_name: dictionary_file_path(migration_name) }]
           end
 
-          bbm_dictionary = RuboCop::BatchedBackgroundMigrationsDictionary.new(version(node))
+          bbm_dictionary = ::Gitlab::Utils::BatchedBackgroundMigrationsDictionary.new(version(node))
 
           return [:missing_key, { key: :milestone }] unless bbm_dictionary.milestone.present?
 
diff --git a/rubocop/cop/migration/unfinished_dependencies.rb b/rubocop/cop/migration/unfinished_dependencies.rb
index 56ba7d405c599a3fefd442417ebf9e67460ffdde..1dda5dc507c96d86679364e9a5c7520cd80af430 100644
--- a/rubocop/cop/migration/unfinished_dependencies.rb
+++ b/rubocop/cop/migration/unfinished_dependencies.rb
@@ -1,7 +1,7 @@
 # frozen_string_literal: true
 
 require_relative '../../migration_helpers'
-require_relative '../../batched_background_migrations_dictionary'
+require_relative '../../../lib/gitlab/utils/batched_background_migrations_dictionary'
 
 module RuboCop
   module Cop
@@ -43,7 +43,9 @@ def on_casgn(node)
         private
 
         def fetch_finalized_by(queued_migration_version)
-          BatchedBackgroundMigrationsDictionary.new(queued_migration_version).finalized_by
+          ::Gitlab::Utils::BatchedBackgroundMigrationsDictionary
+            .new(queued_migration_version)
+            .finalized_by
         end
       end
     end
diff --git a/spec/lib/gitlab/database/background_migration/batched_background_migration_dictionary_spec.rb b/spec/lib/gitlab/database/background_migration/batched_background_migration_dictionary_spec.rb
deleted file mode 100644
index b3aa0c194d226f6ee4e62c025d93d1362a45fe53..0000000000000000000000000000000000000000
--- a/spec/lib/gitlab/database/background_migration/batched_background_migration_dictionary_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Gitlab::Database::BackgroundMigration::BatchedBackgroundMigrationDictionary, feature_category: :database do
-  describe '.entry' do
-    it 'returns a single dictionary entry for the given migration job' do
-      entry = described_class.entry('MigrateHumanUserType')
-      expect(entry.migration_job_name).to eq('MigrateHumanUserType')
-      expect(entry.finalized_by).to eq(20230523101514)
-    end
-  end
-end
diff --git a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
index 404abbe90e10e2e97c78ef5c2e2bc20d18f51c3c..4cc92283430366690d46f71c270593737c651766 100644
--- a/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migrations/batched_background_migration_helpers_spec.rb
@@ -443,6 +443,18 @@ def self.name
     end
   end
 
+  shared_examples 'invalid early finalization' do
+    it 'throws an early finalization error' do
+      expect { ensure_batched_background_migration_is_finished }.to raise_error(described_class::EARLY_FINALIZATION_ERROR)
+    end
+  end
+
+  shared_examples 'valid finalization' do
+    it 'does not throw any error' do
+      expect { ensure_batched_background_migration_is_finished }.not_to raise_error
+    end
+  end
+
   describe '#ensure_batched_background_migration_is_finished' do
     let(:job_class_name) { 'CopyColumnUsingBackgroundMigrationJob' }
     let(:table_name) { '_test_table' }
@@ -461,12 +473,14 @@ def self.name
 
     let(:migration_attributes) do
       configuration.merge(
-        gitlab_schema: gitlab_schema
+        gitlab_schema: gitlab_schema,
+        queued_migration_version: Time.now.utc.strftime("%Y%m%d%H%M%S")
       )
     end
 
     before do
       allow(migration).to receive(:transaction_open?).and_return(false)
+      allow(migration).to receive(:version).and_return('20240905124118')
     end
 
     subject(:ensure_batched_background_migration_is_finished) { migration.ensure_batched_background_migration_is_finished(**configuration) }
@@ -588,5 +602,79 @@ def self.name
         expect { migration.ensure_batched_background_migration_is_finished(**configuration.merge(finalize: false)) }.to raise_error(RuntimeError)
       end
     end
+
+    context 'with finalized migration' do
+      let(:migration_attributes) do
+        configuration
+          .except(:skip_early_finalization_validation)
+          .merge(queued_migration_version: '20240905124118')
+      end
+
+      before do
+        allow(Gitlab::Database::QueryAnalyzers::RestrictAllowedSchemas).to receive(:require_dml_mode!)
+
+        create(:batched_background_migration, :finalized, migration_attributes)
+      end
+
+      context 'when the migration does not have queued_migration_version attr' do
+        let(:migration_attributes) { configuration.merge(queued_migration_version: nil) }
+
+        it_behaves_like 'valid finalization'
+      end
+
+      context 'when the migration version is before ENFORCE_EARLY_FINALIZATION_FROM_VERSION' do
+        let(:migration_attributes) { configuration.merge(queued_migration_version: '20240905124116') }
+
+        it_behaves_like 'valid finalization'
+      end
+
+      context 'when the migration is queued after the last required stop' do
+        before do
+          stub_bbm_stops('16.11', '17.2')
+        end
+
+        it_behaves_like 'invalid early finalization'
+
+        context 'with skip_early_finalization_validation enabled' do
+          let(:configuration) do
+            {
+              job_class_name: job_class_name,
+              table_name: table_name,
+              column_name: column_name,
+              job_arguments: job_arguments,
+              skip_early_finalization_validation: true
+            }
+          end
+
+          it_behaves_like 'valid finalization'
+        end
+      end
+
+      context 'when the migration is queued on the last required stop' do
+        before do
+          stub_bbm_stops('16.11', '16.11')
+        end
+
+        it_behaves_like 'valid finalization'
+      end
+
+      context 'when the migration is queued before the last required stop' do
+        before do
+          stub_bbm_stops('16.11', '16.10')
+        end
+
+        it_behaves_like 'valid finalization'
+      end
+    end
+  end
+
+  def stub_bbm_stops(last_required_stop, queued_milestone)
+    allow_next_instance_of(Gitlab::Utils::BatchedBackgroundMigrationsDictionary) do |dict|
+      allow(dict).to receive(:milestone).and_return(queued_milestone)
+    end
+
+    allow_next_instance_of(Gitlab::Utils::UpgradePath) do |ugrade_path|
+      allow(ugrade_path).to receive(:last_required_stop).and_return(Gitlab::VersionInfo.parse_from_milestone(last_required_stop))
+    end
   end
 end
diff --git a/spec/lib/gitlab/utils/batched_background_migrations_dictionary_spec.rb b/spec/lib/gitlab/utils/batched_background_migrations_dictionary_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6161b6bcc83c10a9d1c653a40a2728df6ce9d989
--- /dev/null
+++ b/spec/lib/gitlab/utils/batched_background_migrations_dictionary_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Utils::BatchedBackgroundMigrationsDictionary, feature_category: :database do
+  let(:bbm_dictionary_file_name) { "#{described_class::DICTIONARY_BASE_DIR}/test_migration.yml" }
+  let(:migration_version) { 20230307160250 }
+  let(:finalized_by) { '20230307160255' }
+  let(:introduced_by_url) { 'https://test_url' }
+  let(:milestone) { '16.5' }
+  let(:migration_job_name) { 'TestMigration' }
+
+  let(:bbm_dictionary_data) do
+    {
+      migration_job_name: migration_job_name,
+      feature_category: :database,
+      introduced_by_url: introduced_by_url,
+      milestone: milestone,
+      queued_migration_version: migration_version,
+      finalized_by: finalized_by
+    }
+  end
+
+  before do
+    File.open(bbm_dictionary_file_name, 'w') do |file|
+      file.write(bbm_dictionary_data.stringify_keys.to_yaml)
+    end
+  end
+
+  after do
+    FileUtils.rm(bbm_dictionary_file_name)
+  end
+
+  subject(:batched_background_migration) { described_class.new(migration_version) }
+
+  describe '.entry' do
+    it 'returns a single dictionary entry for the given migration job' do
+      entry = described_class.entry('TestMigration')
+      expect(entry.migration_job_name).to eq('TestMigration')
+      expect(entry.finalized_by.to_s).to eq(finalized_by)
+    end
+  end
+
+  shared_examples 'safely returns bbm attribute' do |attribute|
+    it 'returns the attr of the bbm' do
+      expect(batched_background_migration.public_send(attribute)).to eq(public_send(attribute))
+    end
+
+    it 'returns nothing for non-existing bbm dictionary' do
+      expect(described_class.new('random').public_send(attribute)).to be_nil
+    end
+  end
+
+  describe '#introduced_by_url' do
+    it_behaves_like 'safely returns bbm attribute', :introduced_by_url
+  end
+
+  describe '#milestone' do
+    it_behaves_like 'safely returns bbm attribute', :milestone
+  end
+
+  describe '#migration_job_name' do
+    it_behaves_like 'safely returns bbm attribute', :migration_job_name
+  end
+
+  describe '.checksum' do
+    let(:entries) { { c: "d", a: "b" } }
+
+    it 'returns a checksum of the entries' do
+      allow(described_class).to receive(:entries).and_return(entries)
+
+      expect(described_class.checksum(skip_memoization: true)).to eq(Digest::SHA256.hexdigest(entries.to_s))
+    end
+  end
+end
diff --git a/spec/rubocop/batched_background_migrations_dictionary_spec.rb b/spec/rubocop/batched_background_migrations_dictionary_spec.rb
deleted file mode 100644
index c6bb9d45fee754152556b087aab96f0efe1c6279..0000000000000000000000000000000000000000
--- a/spec/rubocop/batched_background_migrations_dictionary_spec.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-require 'rubocop_spec_helper'
-
-require_relative '../../rubocop/batched_background_migrations_dictionary'
-
-RSpec.describe RuboCop::BatchedBackgroundMigrationsDictionary, feature_category: :database do
-  let(:bbm_dictionary_file_name) { "#{described_class::DICTIONARY_BASE_DIR}/test_migration.yml" }
-  let(:migration_version) { 20230307160250 }
-  let(:finalized_by_version) { 20230307160255 }
-  let(:introduced_by_url) { 'https://test_url' }
-
-  let(:bbm_dictionary_data) do
-    {
-      migration_job_name: 'TestMigration',
-      feature_category: :database,
-      introduced_by_url: introduced_by_url,
-      milestone: 16.5,
-      queued_migration_version: migration_version,
-      finalized_by: finalized_by_version
-    }
-  end
-
-  before do
-    File.open(bbm_dictionary_file_name, 'w') do |file|
-      file.write(bbm_dictionary_data.stringify_keys.to_yaml)
-    end
-  end
-
-  after do
-    FileUtils.rm(bbm_dictionary_file_name)
-  end
-
-  subject(:batched_background_migration) { described_class.new(migration_version) }
-
-  describe '#finalized_by' do
-    it 'returns the finalized_by version of the bbm with given version',
-      quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/456913' do
-      expect(batched_background_migration.finalized_by).to eq(finalized_by_version.to_s)
-    end
-
-    it 'returns nothing for non-existing bbm dictionary' do
-      expect(described_class.new('random').finalized_by).to be_nil
-    end
-  end
-
-  describe '#introduced_by_url' do
-    it 'returns the introduced_by_url of the bbm with given version',
-      quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/456912' do
-      expect(batched_background_migration.introduced_by_url).to eq(introduced_by_url)
-    end
-
-    it 'returns nothing for non-existing bbm dictionary' do
-      expect(described_class.new('random').introduced_by_url).to be_nil
-    end
-  end
-
-  describe '.checksum' do
-    let(:dictionary_data) { { c: "d", a: "b" } }
-
-    it 'returns a checksum of the dictionary_data' do
-      allow(described_class).to receive(:dictionary_data).and_return(dictionary_data)
-
-      expect(described_class.checksum).to eq(Digest::SHA256.hexdigest(dictionary_data.to_s))
-    end
-  end
-end
diff --git a/spec/rubocop/cop/background_migration/dictionary_file_spec.rb b/spec/rubocop/cop/background_migration/dictionary_file_spec.rb
index 38e6aaf619174e788d99937237a817eec63b7280..3c061136e17158ffa46f5d59d3bdb3ba9b013fdf 100644
--- a/spec/rubocop/cop/background_migration/dictionary_file_spec.rb
+++ b/spec/rubocop/cop/background_migration/dictionary_file_spec.rb
@@ -140,12 +140,13 @@ def up
           before do
             allow(File).to receive(:exist?).and_call_original
             allow(File).to receive(:exist?).with(dictionary_file_path).and_return(true)
-            allow(::RuboCop::BatchedBackgroundMigrationsDictionary).to receive(:dictionary_data).and_return({
-              '20231118100907' => {
-                introduced_by_url: introduced_by_url,
-                milestone: milestone
-              }
-            })
+            allow(Gitlab::Utils::BatchedBackgroundMigrationsDictionary)
+              .to receive(:entries).and_return({
+                '20231118100907' => {
+                  introduced_by_url: introduced_by_url,
+                  milestone: milestone
+                }
+              })
           end
 
           context 'without introduced_by_url' do
@@ -221,8 +222,9 @@ def up
   end
 
   describe '#external_dependency_checksum' do
-    it 'uses the RuboCop::BatchedBackgroundMigrationsDictionary.checksum' do
-      allow(RuboCop::BatchedBackgroundMigrationsDictionary).to receive(:checksum).and_return('aaaaa')
+    it 'uses the Utils::BatchedBackgroundMigrationsDictionary.checksum' do
+      allow(Gitlab::Utils::BatchedBackgroundMigrationsDictionary)
+        .to receive(:checksum).and_return('aaaaa')
 
       expect(cop.external_dependency_checksum).to eq('aaaaa')
     end
diff --git a/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb b/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb
index f2e963ad3222d254fef46973ea039cdd0a746d08..05ac56105f69f8da7d469b5da39919f8ce96de61 100644
--- a/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb
+++ b/spec/rubocop/cop/migration/unfinished_dependencies_spec.rb
@@ -99,7 +99,7 @@ def perform; end
 
     context 'with properly finalized dependent background migrations' do
       before do
-        allow_next_instance_of(RuboCop::BatchedBackgroundMigrationsDictionary) do |bbms|
+        allow_next_instance_of(Gitlab::Utils::BatchedBackgroundMigrationsDictionary) do |bbms|
           allow(bbms).to receive(:finalized_by).and_return(version - 5)
         end
       end
diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb
index 97869fc12fc660ee9673a2c9b81b0a273a4863cb..1140daa2acda3280273ef36271d975b8074ca081 100644
--- a/spec/support/helpers/migrations_helpers.rb
+++ b/spec/support/helpers/migrations_helpers.rb
@@ -141,10 +141,10 @@ def previous_migration(steps_back = 2)
   end
 
   def finalized_by_version
-    finalized_by = ::Gitlab::Database::BackgroundMigration::BatchedBackgroundMigrationDictionary
+    finalized_by = ::Gitlab::Utils::BatchedBackgroundMigrationsDictionary
       .entry(described_class.to_s.demodulize)&.finalized_by
 
-    finalized_by.to_i if finalized_by
+    finalized_by.to_i if finalized_by.present?
   end
 
   def migration_schema_version
diff --git a/spec/support_specs/helpers/migrations_helpers_spec.rb b/spec/support_specs/helpers/migrations_helpers_spec.rb
index 6587234a90589630795b3ff215462d796fdc6abe..216a3fc373f69aba1b1b2b1a8c6611acdf8312d0 100644
--- a/spec/support_specs/helpers/migrations_helpers_spec.rb
+++ b/spec/support_specs/helpers/migrations_helpers_spec.rb
@@ -113,7 +113,7 @@
 
     before do
       allow(helper).to receive(:described_class)
-      allow(::Gitlab::Database::BackgroundMigration::BatchedBackgroundMigrationDictionary).to(
+      allow(::Gitlab::Utils::BatchedBackgroundMigrationsDictionary).to(
         receive(:entry).and_return(dictionary_entry)
       )
     end
@@ -125,7 +125,7 @@
     context 'when finalized_by is a string' do
       let(:dictionary_entry) do
         instance_double(
-          ::Gitlab::Database::BackgroundMigration::BatchedBackgroundMigrationDictionary::Entry,
+          ::Gitlab::Utils::BatchedBackgroundMigrationsDictionary,
           finalized_by: '20240104155616'
         )
       end