diff --git a/.rubocop.yml b/.rubocop.yml
index 46bfbc38609db390728ddf18d2dfe2229bf9d072..5a42f393ed30c226299e48bc0e56e22523c8c182 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -11,7 +11,6 @@ inherit_from:
     <% Dir.glob('.rubocop_todo/**/*.yml').each do |rubocop_todo_yaml| %>
   - '<%= rubocop_todo_yaml %>'
     <% end %>
-  - '.rubocop_todo.yml'
   <% end %>
   - ./rubocop/rubocop-migrations.yml
   - ./rubocop/rubocop-usage-data.yml
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
deleted file mode 100644
index 72ce67b08dae4e38bca59182bdf99a7439693ae8..0000000000000000000000000000000000000000
--- a/.rubocop_todo.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-# This configuration is no longer used.
-#
-# The RuboCop TODO lists are located in `.rubocop_todo/**/*.yml`.
-#
-# Please use `rake rubocop:todo:generate` to generate TODOs.
-#
-# See https://docs.gitlab.com/ee/development/rake_tasks.html#generate-initial-rubocop-todo-list
diff --git a/doc/development/rubocop_development_guide.md b/doc/development/rubocop_development_guide.md
index c2a6fbff05a1e26127028275a63525736d5b41ab..e4dbd4f845e9728ea170cb265a0865bd4fa7caca 100644
--- a/doc/development/rubocop_development_guide.md
+++ b/doc/development/rubocop_development_guide.md
@@ -178,7 +178,7 @@ and run `bundle exec gitlab-housekeeper -k Keeps::GenerateRubocopTodos`.
 
 ## Reveal existing RuboCop exceptions
 
-To reveal existing RuboCop exceptions in the code that have been excluded via `.rubocop_todo.yml` and
+To reveal existing RuboCop exceptions in the code that have been excluded via
 `.rubocop_todo/**/*.yml`, set the environment variable `REVEAL_RUBOCOP_TODO` to `1`.
 
 This allows you to reveal existing RuboCop exceptions during your daily work cycle and fix them along the way.
diff --git a/rubocop/formatter/todo_formatter.rb b/rubocop/formatter/todo_formatter.rb
index cbdc20e2fdab0f1f1575ec5bb59b9df4a8555bb9..ee81c5daf064bc1790d3f21758b21f7159b46ddc 100644
--- a/rubocop/formatter/todo_formatter.rb
+++ b/rubocop/formatter/todo_formatter.rb
@@ -35,8 +35,6 @@ def initialize(output, _options = {})
         @todos = Hash.new { |hash, cop_name| hash[cop_name] = CopTodo.new(cop_name) }
         @todo_dir = TodoDir.new(directory)
         @config_inspect_todo_dir = load_config_inspect_todo_dir
-        @config_old_todo_yml = load_config_old_todo_yml
-        check_multiple_configurations!
         create_todos_retaining_exclusions(@config_inspect_todo_dir)
 
         super
@@ -79,14 +77,6 @@ def relative_path(path)
         path.delete_prefix("#{parent}/")
       end
 
-      def check_multiple_configurations!
-        cop_names = @config_inspect_todo_dir.keys & @config_old_todo_yml.keys
-        return if cop_names.empty?
-
-        list = cop_names.sort.map { |cop_name| "- #{cop_name}" }.join("\n")
-        raise "Multiple configurations found for cops:\n#{list}\n"
-      end
-
       def create_todos_retaining_exclusions(inspected_cop_config)
         inspected_cop_config.each do |cop_name, config|
           todo = @todos[cop_name]
@@ -98,7 +88,7 @@ def create_todos_retaining_exclusions(inspected_cop_config)
       def config_for(todo)
         cop_name = todo.cop_name
 
-        @config_old_todo_yml[cop_name] || @config_inspect_todo_dir[cop_name] || {}
+        @config_inspect_todo_dir[cop_name] || {}
       end
 
       def previously_disabled?(todo)
@@ -131,15 +121,6 @@ def load_config_inspect_todo_dir
           combined.update(config) if Hash === config
         end
       end
-
-      # Load YAML configuration from `.rubocop_todo.yml`.
-      # We consider this file already old, obsolete, and to be removed soon.
-      def load_config_old_todo_yml
-        path = File.expand_path(File.join(directory, '../.rubocop_todo.yml'))
-        config = YAML.load_file(path) if File.exist?(path)
-
-        config || {}
-      end
     end
   end
 end
diff --git a/spec/rubocop/formatter/graceful_formatter_spec.rb b/spec/rubocop/formatter/graceful_formatter_spec.rb
index b9a56bec115897098ed75debf527cf82e6cf5a26..a2c52ff1d8d39f15838e2672082c53fe9cac2872 100644
--- a/spec/rubocop/formatter/graceful_formatter_spec.rb
+++ b/spec/rubocop/formatter/graceful_formatter_spec.rb
@@ -7,7 +7,7 @@
 require_relative '../../../rubocop/formatter/graceful_formatter'
 require_relative '../../../rubocop/todo_dir'
 
-RSpec.describe RuboCop::Formatter::GracefulFormatter, :isolated_environment do
+RSpec.describe RuboCop::Formatter::GracefulFormatter, :isolated_environment, feature_category: :tooling do
   # Set by :isolated_environment
   let(:todo_dir) { RuboCop::TodoDir.new("#{Dir.pwd}/.rubocop_todo") }
   let(:stdout) { StringIO.new }
@@ -43,14 +43,11 @@
     let(:offense2) { fake_offense('Cop2') }
 
     before do
-      FileUtils.touch('.rubocop_todo.yml')
-
       File.write('.rubocop.yml', <<~YAML)
         inherit_from:
           <% Dir.glob('.rubocop_todo/**/*.yml').each do |rubocop_todo_yaml| %>
           - '<%= rubocop_todo_yaml %>'
           <% end %>
-          - '.rubocop_todo.yml'
 
         AllCops:
           NewCops: enable # Avoiding RuboCop warnings
@@ -80,7 +77,7 @@
           Details: grace period
         YAML
 
-        File.write('.rubocop_todo.yml', <<~YAML)
+        todo_dir.write('Cop2', <<~YAML)
         ---
         Cop2:
           Details: grace period
diff --git a/spec/rubocop/formatter/todo_formatter_spec.rb b/spec/rubocop/formatter/todo_formatter_spec.rb
index f82de678b11366db1e9f656025cc66f4d9edb351..146dc31518dcd7d52659896e547331357b967fe1 100644
--- a/spec/rubocop/formatter/todo_formatter_spec.rb
+++ b/spec/rubocop/formatter/todo_formatter_spec.rb
@@ -200,35 +200,6 @@ def run_formatter
       end
     end
 
-    context 'when cop previously explicitly disabled in rubocop_todo.yml' do
-      before do
-        File.write('.rubocop_todo.yml', <<~YAML)
-          ---
-          B/TooManyOffenses:
-            Enabled: false
-            Exclude:
-              - 'x.rb'
-        YAML
-
-        todo_dir.inspect_all
-      end
-
-      it 'keeps cop disabled' do
-        run_formatter
-
-        expect(todo_yml('B/TooManyOffenses')).to eq(<<~YAML)
-          ---
-          B/TooManyOffenses:
-            # Offense count: 3
-            # Temporarily disabled due to too many offenses
-            Enabled: false
-            Exclude:
-              - 'a.rb'
-              - 'c.rb'
-        YAML
-      end
-    end
-
     context 'with grace period' do
       let(:yaml) do
         <<~YAML
@@ -240,6 +211,11 @@ def run_formatter
         YAML
       end
 
+      before do
+        todo_dir.write('B/TooManyOffenses', yaml)
+        todo_dir.inspect_all
+      end
+
       shared_examples 'keeps grace period' do
         it 'keeps Details: grace period' do
           run_formatter
@@ -255,22 +231,7 @@ def run_formatter
         end
       end
 
-      context 'in rubocop_todo/' do
-        before do
-          todo_dir.write('B/TooManyOffenses', yaml)
-          todo_dir.inspect_all
-        end
-
-        it_behaves_like 'keeps grace period'
-      end
-
-      context 'in rubocop_todo.yml' do
-        before do
-          File.write('.rubocop_todo.yml', yaml)
-        end
-
-        it_behaves_like 'keeps grace period'
-      end
+      it_behaves_like 'keeps grace period'
 
       context 'with invalid details value' do
         let(:yaml) do
@@ -284,8 +245,6 @@ def run_formatter
         end
 
         it 'ignores the details and warns' do
-          File.write('.rubocop_todo.yml', yaml)
-
           expect { run_formatter }
             .to output(%r{B/TooManyOffenses: Unhandled value "something unknown" for `Details` key.})
             .to_stderr
@@ -313,51 +272,11 @@ def run_formatter
         end
 
         it 'raises an exception' do
-          File.write('.rubocop_todo.yml', yaml)
-
           expect { run_formatter }
             .to raise_error(RuntimeError, 'B/TooManyOffenses: Cop must be enabled to use `Details: grace period`.')
         end
       end
     end
-
-    context 'with cop configuration in both .rubocop_todo/ and .rubocop_todo.yml' do
-      before do
-        todo_dir.write('B/TooManyOffenses', <<~YAML)
-          ---
-          B/TooManyOffenses:
-            Exclude:
-              - 'a.rb'
-        YAML
-
-        todo_dir.write('A/Offense', <<~YAML)
-          ---
-          A/Offense:
-            Exclude:
-              - 'a.rb'
-        YAML
-
-        todo_dir.inspect_all
-
-        File.write('.rubocop_todo.yml', <<~YAML)
-          ---
-          B/TooManyOffenses:
-            Exclude:
-              - 'x.rb'
-          A/Offense:
-            Exclude:
-              - 'y.rb'
-        YAML
-      end
-
-      it 'raises an error' do
-        expect { run_formatter }.to raise_error(RuntimeError, <<~TXT)
-          Multiple configurations found for cops:
-          - A/Offense
-          - B/TooManyOffenses
-        TXT
-      end
-    end
   end
 
   context 'without offenses detected' do
diff --git a/spec/tasks/rubocop_rake_spec.rb b/spec/tasks/rubocop_rake_spec.rb
index 2a8b6bb35eae7efa5e55eb34b6bf2a3ce78f7e86..2dff7fdaf0956d42f42cc8963eede33b8d16f6de 100644
--- a/spec/tasks/rubocop_rake_spec.rb
+++ b/spec/tasks/rubocop_rake_spec.rb
@@ -12,7 +12,7 @@
 require_relative '../../rubocop/todo_dir'
 require_relative '../../rubocop/check_graceful_task'
 
-RSpec.describe 'rubocop rake tasks', :silence_stdout do
+RSpec.describe 'rubocop rake tasks', :silence_stdout, feature_category: :tooling do
   include NextInstanceOf
 
   before do
@@ -81,14 +81,13 @@
 
       RUBY
 
-      # Mimicking GitLab's .rubocop_todo.yml avoids relying on RuboCop's
+      # Mimicking GitLab's .rubocop_todo/**/*.yml avoids relying on RuboCop's
       # default.yml configuration.
       File.write('.rubocop.yml', <<~YAML)
         <% unless ENV['REVEAL_RUBOCOP_TODO'] == '1' %>
           <% Dir.glob('.rubocop_todo/**/*.yml').each do |rubocop_todo_yaml| %>
         - '<%= rubocop_todo_yaml %>'
           <% end %>
-        - '.rubocop_todo.yml'
         <% end %>
 
         AllCops:
@@ -107,16 +106,6 @@
           Enabled: true
       YAML
 
-      # Required to verify that we are revealing all TODOs via
-      # ENV['REVEAL_RUBOCOP_TODO'] = '1'.
-      # This file can be removed from specs after we've moved all offenses from
-      # .rubocop_todo.yml to .rubocop_todo/**/*.yml.
-      File.write('.rubocop_todo.yml', <<~YAML)
-        # Too many offenses
-        Layout/SpaceAroundOperators:
-          Enabled: false
-      YAML
-
       # Previous offense now fixed.
       todo_dir.write('Lint/Syntax', '')
     end
diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb
index 43fd8ba365111d0cb94d489e860a968ba513879d..c7cf8c6c5132aa8cfe08ff36c5352a68b3965022 100644
--- a/spec/tooling/danger/project_helper_spec.rb
+++ b/spec/tooling/danger/project_helper_spec.rb
@@ -90,7 +90,6 @@
       'lib/foo'                    | [:backend]
       'rubocop/foo'                | [:backend]
       '.rubocop.yml'               | [:backend]
-      '.rubocop_todo.yml'          | [:backend]
       '.rubocop_todo/cop/name.yml' | [:backend]
       'gems/foo/.rubocop.yml'      | [:backend]
       'spec/foo'                   | [:backend]
diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb
index 846b76c8b019be52b2a4e728413d691dc628fbe3..76d24a8926d14e42b448c9fc6810d29109b29537 100644
--- a/tooling/danger/project_helper.rb
+++ b/tooling/danger/project_helper.rb
@@ -144,7 +144,7 @@ module ProjectHelper
         %r{\A((ee|jh)/)?vendor/} => :backend,
         %r{\A(Gemfile.*|Rakefile)\z} => :backend,
         %r{\A[A-Z_]+_VERSION\z} => :backend,
-        %r{\A\.rubocop(_todo)?\.yml\z} => :backend,
+        %r{\A\.rubocop\.yml\z} => :backend,
         %r{\Agems/.*/\.rubocop\.yml\z} => :backend,
         %r{\A\.rubocop_todo/.*\.yml\z} => :backend,
         %r{\Afile_hooks/} => :backend,