diff --git a/changelogs/unreleased/28017-separate-ce-params-on-api.yml b/changelogs/unreleased/28017-separate-ce-params-on-api.yml
new file mode 100644
index 0000000000000000000000000000000000000000..039a8d207b00b2f43eb47255e3b413a7a2d22f6e
--- /dev/null
+++ b/changelogs/unreleased/28017-separate-ce-params-on-api.yml
@@ -0,0 +1,4 @@
+---
+title: Separate CE params on Grape API
+merge_request:
+author:
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 32bbf956d7fd6d98e519e44288129b3a07d9a9e4..073c0145cd82db2401d24bc62abe7acedecf7dde 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -5,13 +5,17 @@ module API
     before { authenticate! }
 
     helpers do
-      params :optional_params do
+      params :optional_params_ce do
         optional :description, type: String, desc: 'The description of the group'
         optional :visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The visibility of the group'
         optional :lfs_enabled, type: Boolean, desc: 'Enable/disable LFS for the projects in this group'
         optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access'
       end
 
+      params :optional_params do
+        use :optional_params_ce
+      end
+
       params :statistics_params do
         optional :statistics, type: Boolean, default: false, desc: 'Include project statistics'
       end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 09053e615cb3ea85d7b30970dd352c8520709426..05423c174498059be3010e5aad0353bab16f63b5 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -30,7 +30,7 @@ module API
         use :pagination
       end
 
-      params :issue_params do
+      params :issue_params_ce do
         optional :description, type: String, desc: 'The description of an issue'
         optional :assignee_id, type: Integer, desc: 'The ID of a user to assign issue'
         optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign issue'
@@ -38,6 +38,10 @@ module API
         optional :due_date, type: String, desc: 'Date time string in the format YEAR-MONTH-DAY'
         optional :confidential, type: Boolean, desc: 'Boolean parameter if the issue should be confidential'
       end
+
+      params :issue_params do
+        use :issue_params_ce
+      end
     end
 
     resource :issues do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index c8033664133886e997f6ab25b1cce383a92146f3..cb7aec47cf0c1bcf5e9312df206c6fe9c6d1724a 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -33,13 +33,17 @@ module API
           end
         end
 
-        params :optional_params do
+        params :optional_params_ce do
           optional :description, type: String, desc: 'The description of the merge request'
           optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request'
           optional :milestone_id, type: Integer, desc: 'The ID of a milestone to assign the merge request'
           optional :labels, type: String, desc: 'Comma-separated list of label names'
           optional :remove_source_branch, type: Boolean, desc: 'Remove source branch when merging'
         end
+
+        params :optional_params do
+          use :optional_params_ce
+        end
       end
 
       desc 'List merge requests' do
@@ -145,14 +149,24 @@ module API
         success Entities::MergeRequest
       end
       params do
+        # CE
+        at_least_one_of_ce = [
+          :assignee_id,
+          :description,
+          :labels,
+          :milestone_id,
+          :remove_source_branch,
+          :state_event,
+          :target_branch,
+          :title
+        ]
         optional :title, type: String, allow_blank: false, desc: 'The title of the merge request'
         optional :target_branch, type: String, allow_blank: false, desc: 'The target branch'
         optional :state_event, type: String, values: %w[close reopen],
                                desc: 'Status of the merge request'
+
         use :optional_params
-        at_least_one_of :title, :target_branch, :description, :assignee_id,
-                        :milestone_id, :labels, :state_event,
-                        :remove_source_branch
+        at_least_one_of(*at_least_one_of_ce)
       end
       put ':id/merge_requests/:merge_request_iid' do
         merge_request = find_merge_request_with_access(params.delete(:merge_request_iid), :update_merge_request)
@@ -173,6 +187,7 @@ module API
         success Entities::MergeRequest
       end
       params do
+        # CE
         optional :merge_commit_message, type: String, desc: 'Custom merge commit message'
         optional :should_remove_source_branch, type: Boolean,
                                                desc: 'When true, the source branch will be deleted if possible'
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 766fbea53e6b67895effca989c38264f00d57a65..5084237094719af61b1404d818c99daf09262aba 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -6,7 +6,7 @@ module API
     before { authenticate_non_get! }
 
     helpers do
-      params :optional_params do
+      params :optional_params_ce do
         optional :description, type: String, desc: 'The description of the project'
         optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled'
         optional :merge_requests_enabled, type: Boolean, desc: 'Flag indication if merge requests are enabled'
@@ -22,6 +22,10 @@ module API
         optional :only_allow_merge_if_pipeline_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed'
         optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved'
       end
+
+      params :optional_params do
+        use :optional_params_ce
+      end
     end
 
     resource :projects do
@@ -198,17 +202,33 @@ module API
         success Entities::Project
       end
       params do
+        # CE
+        at_least_one_of_ce =
+          [
+            :builds_enabled,
+            :container_registry_enabled,
+            :default_branch,
+            :description,
+            :issues_enabled,
+            :lfs_enabled,
+            :merge_requests_enabled,
+            :name,
+            :only_allow_merge_if_all_discussions_are_resolved,
+            :only_allow_merge_if_pipeline_succeeds,
+            :path,
+            :public_builds,
+            :request_access_enabled,
+            :shared_runners_enabled,
+            :snippets_enabled,
+            :visibility,
+            :wiki_enabled,
+          ]
         optional :name, type: String, desc: 'The name of the project'
         optional :default_branch, type: String, desc: 'The default branch of the project'
         optional :path, type: String, desc: 'The path of the repository'
+
         use :optional_params
-        at_least_one_of :name, :description, :issues_enabled, :merge_requests_enabled,
-                        :wiki_enabled, :builds_enabled, :snippets_enabled,
-                        :shared_runners_enabled, :container_registry_enabled,
-                        :lfs_enabled, :visibility, :public_builds,
-                        :request_access_enabled, :only_allow_merge_if_pipeline_succeeds,
-                        :only_allow_merge_if_all_discussions_are_resolved, :path,
-                        :default_branch
+        at_least_one_of(*at_least_one_of_ce)
       end
       put ':id' do
         authorize_admin_project
diff --git a/lib/api/settings.rb b/lib/api/settings.rb
index c7f97ad2aab61bc36c6b947732c274ff45bf93f2..d01c7f2703b96a372f121c9e7b03595905f76946 100644
--- a/lib/api/settings.rb
+++ b/lib/api/settings.rb
@@ -20,6 +20,55 @@ module API
       success Entities::ApplicationSetting
     end
     params do
+      # CE
+      at_least_one_of_ce = [
+        :admin_notification_email,
+        :after_sign_out_path,
+        :after_sign_up_text,
+        :akismet_enabled,
+        :container_registry_token_expire_delay,
+        :default_artifacts_expire_in,
+        :default_branch_protection,
+        :default_group_visibility,
+        :default_project_visibility,
+        :default_projects_limit,
+        :default_snippet_visibility,
+        :disabled_oauth_sign_in_sources,
+        :domain_blacklist_enabled,
+        :domain_whitelist,
+        :email_author_in_body,
+        :enabled_git_access_protocol,
+        :gravatar_enabled,
+        :help_page_text,
+        :home_page_url,
+        :housekeeping_enabled,
+        :html_emails_enabled,
+        :import_sources,
+        :koding_enabled,
+        :max_artifacts_size,
+        :max_attachment_size,
+        :max_pages_size,
+        :metrics_enabled,
+        :plantuml_enabled,
+        :polling_interval_multiplier,
+        :recaptcha_enabled,
+        :repository_checks_enabled,
+        :repository_storage,
+        :require_two_factor_authentication,
+        :restricted_visibility_levels,
+        :send_user_confirmation_email,
+        :sentry_enabled,
+        :session_expire_delay,
+        :shared_runners_enabled,
+        :sidekiq_throttling_enabled,
+        :sign_in_text,
+        :signin_enabled,
+        :signup_enabled,
+        :terminal_max_session_time,
+        :user_default_external,
+        :user_oauth_applications,
+        :version_check_enabled
+      ]
       optional :default_branch_protection, type: Integer, values: [0, 1, 2], desc: 'Determine if developers can push to master'
       optional :default_project_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default project visibility'
       optional :default_snippet_visibility, type: String, values: Gitlab::VisibilityLevel.string_values, desc: 'The default snippet visibility'
@@ -111,22 +160,8 @@ module API
       end
       optional :terminal_max_session_time, type: Integer, desc: 'Maximum time for web terminal websocket connection (in seconds). Set to 0 for unlimited time.'
       optional :polling_interval_multiplier, type: BigDecimal, desc: 'Interval multiplier used by endpoints that perform polling. Set to 0 to disable polling.'
-      at_least_one_of :default_branch_protection, :default_project_visibility, :default_snippet_visibility,
-                      :default_group_visibility, :restricted_visibility_levels, :import_sources,
-                      :enabled_git_access_protocol, :gravatar_enabled, :default_projects_limit,
-                      :max_attachment_size, :session_expire_delay, :disabled_oauth_sign_in_sources,
-                      :user_oauth_applications, :user_default_external, :signup_enabled,
-                      :send_user_confirmation_email, :domain_whitelist, :domain_blacklist_enabled,
-                      :after_sign_up_text, :signin_enabled, :require_two_factor_authentication,
-                      :home_page_url, :after_sign_out_path, :sign_in_text, :help_page_text,
-                      :shared_runners_enabled, :max_artifacts_size,
-                      :default_artifacts_expire_in, :max_pages_size,
-                      :container_registry_token_expire_delay,
-                      :metrics_enabled, :sidekiq_throttling_enabled, :recaptcha_enabled,
-                      :akismet_enabled, :admin_notification_email, :sentry_enabled,
-                      :repository_storage, :repository_checks_enabled, :koding_enabled, :plantuml_enabled,
-                      :version_check_enabled, :email_author_in_body, :html_emails_enabled,
-                      :housekeeping_enabled, :terminal_max_session_time, :polling_interval_multiplier
+
+      at_least_one_of(*at_least_one_of_ce)
     end
     put "application/settings" do
       attrs = declared_params(include_missing: false)
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 6f40f92240a396b2c6d57d620224abf59185861d..eedc59f86368c89dfd103ecef769d6cca07bf7d2 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -37,11 +37,13 @@ module API
         success Entities::UserBasic
       end
       params do
+        # CE
         optional :username, type: String, desc: 'Get a single user with a specific username'
         optional :search, type: String, desc: 'Search for a username'
         optional :active, type: Boolean, default: false, desc: 'Filters only active users'
         optional :external, type: Boolean, default: false, desc: 'Filters only external users'
         optional :blocked, type: Boolean, default: false, desc: 'Filters only blocked users'
+
         use :pagination
       end
       get do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 2e291eb3ceafbe4d8188f78a7c14b6255fd0cd11..74bc484724757a8e40c0152b70621345fec192c0 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1076,6 +1076,13 @@ describe API::Projects, :api  do
     before { project_member3 }
     before { project_member2 }
 
+    it 'returns 400 when nothing sent' do
+      project_param = {}
+      put api("/projects/#{project.id}", user), project_param
+      expect(response).to have_http_status(400)
+      expect(json_response['error']).to match('at least one parameter must be provided')
+    end
+
     context 'when unauthenticated' do
       it 'returns authentication error' do
         project_param = { name: 'bar' }