diff --git a/app/experiments/empty_repo_upload_experiment.rb b/app/experiments/empty_repo_upload_experiment.rb
deleted file mode 100644
index c8c75f32d69c581ccba4e8209be73e3079594c3c..0000000000000000000000000000000000000000
--- a/app/experiments/empty_repo_upload_experiment.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# frozen_string_literal: true
-
-class EmptyRepoUploadExperiment < ApplicationExperiment
-  include ProjectCommitCount
-
-  TRACKING_START_DATE = DateTime.parse('2021/4/20')
-  INITIAL_COMMIT_COUNT = 1
-
-  def track_initial_write
-    return unless should_track? # early return if we don't need to ask for commit counts
-    return unless context.project.created_at > TRACKING_START_DATE # early return for older projects
-    return unless commit_count == INITIAL_COMMIT_COUNT
-
-    track(:initial_write, project: context.project)
-  end
-
-  private
-
-  def commit_count
-    commit_count_for(context.project, max_count: INITIAL_COMMIT_COUNT, experiment: name)
-  end
-end
diff --git a/app/experiments/force_company_trial_experiment.rb b/app/experiments/force_company_trial_experiment.rb
deleted file mode 100644
index e7b98bb18ad04e43796a9f22e2c29494b2d5ada6..0000000000000000000000000000000000000000
--- a/app/experiments/force_company_trial_experiment.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-# frozen_string_literal: true
-
-class ForceCompanyTrialExperiment < ApplicationExperiment
-  exclude :setup_for_personal
-
-  private
-
-  def setup_for_personal
-    !context.user.setup_for_company
-  end
-end
diff --git a/app/experiments/logged_out_marketing_header_experiment.rb b/app/experiments/logged_out_marketing_header_experiment.rb
deleted file mode 100644
index 3d88d94aec402c9a0012d3fd6b04be3b00fee379..0000000000000000000000000000000000000000
--- a/app/experiments/logged_out_marketing_header_experiment.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-class LoggedOutMarketingHeaderExperiment < ApplicationExperiment
-  # These default behaviors are overriden in ApplicationHelper and header
-  # template partial
-  control {}
-  candidate {}
-  variant(:trial_focused) {}
-end
diff --git a/danger/experiments/Dangerfile b/danger/experiments/Dangerfile
new file mode 100644
index 0000000000000000000000000000000000000000..3a206bc876e3f21383dedd8844534003fe4e23b1
--- /dev/null
+++ b/danger/experiments/Dangerfile
@@ -0,0 +1,7 @@
+# frozen_string_literal: true
+
+unless experiments.class_files_removed?
+  msg = "This merge request removes experiment: `#{experiments.removed_experiments.join(',')}`" \
+        ", please also remove the class file."
+  fail msg # rubocop:disable Style/SignalException
+end
diff --git a/danger/plugins/experiments.rb b/danger/plugins/experiments.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b7fd6573c306a85d4701f69727d4e157b2674d40
--- /dev/null
+++ b/danger/plugins/experiments.rb
@@ -0,0 +1,10 @@
+# frozen_string_literal: true
+
+require_relative '../../tooling/danger/experiments'
+
+module Danger
+  class Experiments < ::Danger::Plugin
+    # Put the helper code somewhere it can be tested
+    include Tooling::Danger::Experiments
+  end
+end
diff --git a/spec/experiments/force_company_trial_experiment_spec.rb b/spec/experiments/force_company_trial_experiment_spec.rb
deleted file mode 100644
index 42a3245771aab92e33a75af4bcd32da71b84d502..0000000000000000000000000000000000000000
--- a/spec/experiments/force_company_trial_experiment_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ForceCompanyTrialExperiment, :experiment do
-  subject { described_class.new(current_user: user) }
-
-  let(:user) { create(:user, setup_for_company: setup_for_company) }
-  let(:setup_for_company) { true }
-
-  context 'when a user is setup_for_company' do
-    it 'is not excluded' do
-      expect(subject).not_to exclude(user: user)
-    end
-  end
-
-  context 'when a user is not setup_for_company' do
-    let(:setup_for_company) { nil }
-
-    it 'is excluded' do
-      expect(subject).to exclude(user: user)
-    end
-  end
-end
diff --git a/spec/tooling/danger/experiments_spec.rb b/spec/tooling/danger/experiments_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..85f8060a3ec4757469ad534448e7f032c7d7cc53
--- /dev/null
+++ b/spec/tooling/danger/experiments_spec.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+require 'gitlab-dangerfiles'
+require 'gitlab/dangerfiles/spec_helper'
+
+require_relative '../../../tooling/danger/experiments'
+
+RSpec.describe Tooling::Danger::Experiments, feature_category: :tooling do
+  include_context "with dangerfile"
+
+  let(:fake_danger) { DangerSpecHelper.fake_danger.include(described_class) }
+
+  subject(:experiments) { fake_danger.new(helper: fake_helper) }
+
+  describe '#removed_experiments' do
+    let(:removed_experiments_yml_files) do
+      [
+        'config/feature_flags/experiment/tier_badge.yml',
+        'ee/config/feature_flags/experiment/direct_to_trial.yml'
+      ]
+    end
+
+    let(:deleted_files) do
+      [
+        'app/models/model.rb',
+        'app/assets/javascripts/file.js'
+      ] + removed_experiments_yml_files
+    end
+
+    it 'returns names of removed experiments' do
+      expect(experiments.removed_experiments).to eq(%w[tier_badge direct_to_trial])
+    end
+  end
+
+  describe '#class_files_removed?' do
+    let(:removed_experiments_name) { current_experiment_with_class_files_example }
+
+    context 'when yml file is deleted but not class file' do
+      let(:deleted_files) { ["config/feature_flags/experiment/#{removed_experiments_name}.yml"] }
+
+      it 'returns false' do
+        expect(experiments.class_files_removed?).to eq(false)
+      end
+    end
+
+    context 'when yml file is deleted but no corresponding class file exists' do
+      let(:deleted_files) { ["config/feature_flags/experiment/fake_experiment.yml"] }
+
+      it 'returns true' do
+        expect(experiments.class_files_removed?).to eq(true)
+      end
+    end
+  end
+
+  def current_experiment_with_class_files_example
+    path = Dir.glob("app/experiments/*.rb").last
+    File.basename(path).chomp('_experiment.rb')
+  end
+end
diff --git a/tooling/danger/experiments.rb b/tooling/danger/experiments.rb
new file mode 100644
index 0000000000000000000000000000000000000000..49489419bab54189c2dae1cedb582df8dadfa2ad
--- /dev/null
+++ b/tooling/danger/experiments.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+module Tooling
+  module Danger
+    module Experiments
+      EXPERIMENTS_YML_REGEX = %r{\A(ee/)?config/feature_flags/experiment/}
+      CLASS_FILES_DIR = %w[app/experiments/ ee/app/experiments/].freeze
+
+      def class_files_removed?
+        (removed_experiments & current_experiments_with_class_files).empty?
+      end
+
+      def removed_experiments
+        yml_files_paths = helper.deleted_files
+
+        yml_files_paths.select { |path| path =~ EXPERIMENTS_YML_REGEX }.map { |path| File.basename(path).chomp('.yml') }
+      end
+
+      private
+
+      def current_experiments_with_class_files
+        experiment_names = []
+
+        CLASS_FILES_DIR.each do |directory_path|
+          experiment_names += Dir.glob("#{directory_path}*.rb").map do |path|
+            File.basename(path).chomp('_experiment.rb')
+          end
+        end
+
+        experiment_names
+      end
+    end
+  end
+end