diff --git a/app/assets/javascripts/categories.js b/app/assets/javascripts/categories.js
index 8b766b11ba22e3014b8edfb5729ce1858a42935b..30c37d2dccf07dc7bc22ec0267b503c6fc47d936 100644
--- a/app/assets/javascripts/categories.js
+++ b/app/assets/javascripts/categories.js
@@ -10,7 +10,7 @@ $(() => {
         $caption.find('[data-state="absent"]').hide();
         $caption.find('[data-state="present"]').show();
 
-        $el.find('.js-tag-select').attr('data-tag-set', tagSetId);
+        $el.find('.js-tag-select').attr('data-tag-set', tagSetId).attr('disabled', false);
       });
     }
     else {
@@ -20,7 +20,7 @@ $(() => {
         $caption.find('[data-state="absent"]').show();
         $caption.find('[data-state="present"]').hide();
 
-        $el.find('.js-tag-select').attr('data-tag-set', null);
+        $el.find('.js-tag-select').attr('data-tag-set', null).attr('disabled', true);
       });
     }
   });
diff --git a/app/assets/javascripts/tags.js b/app/assets/javascripts/tags.js
index 3b07c93a3c9a5984ed97a33af79d3c6115e74d90..be3e3af18223b017acd217b90193bfc1f3d3f95b 100644
--- a/app/assets/javascripts/tags.js
+++ b/app/assets/javascripts/tags.js
@@ -1,6 +1,7 @@
 $(() => {
   $('.js-tag-select').each((i, el) => {
     const $tgt = $(el);
+    const useIds = $tgt.attr('data-use-ids') === 'true';
     $tgt.select2({
       tags: $tgt.attr('data-create') !== 'false',
       ajax: {
@@ -10,7 +11,7 @@ $(() => {
         },
         headers: { 'Accept': 'application/json' },
         delay: 100,
-        processResults: data => ({results: data.map(t => ({id: t.name, text: t.name}))}),
+        processResults: data => ({results: data.map(t => ({id: useIds ? t.id : t.name, text: t.name}))}),
       }
     });
   });
diff --git a/app/views/categories/_form.html.erb b/app/views/categories/_form.html.erb
index 95a830f61756bd1b16766c982e6fbc12baaa3226..776a3bc7d0b955fba45014451ffca91d899182c8 100644
--- a/app/views/categories/_form.html.erb
+++ b/app/views/categories/_form.html.erb
@@ -100,10 +100,11 @@
         Select a tag set first.
       </span>
     </span>
+    <% disabled = @category.tag_set.nil? %>
     <%= f.select :required_tag_ids, options_for_select(@category.required_tags.map { |t| [t.name, t.id] },
                                                        selected: @category.required_tags.pluck(:name)),
                  { include_blank: true }, multiple: true, class: 'form-element js-tag-select',
-                 data: { tag_set: @category.tag_set&.id, create: 'false' } %>
+                 data: { tag_set: @category.tag_set&.id, create: 'false', use_ids: 'true' }, disabled: disabled %>
   </div>
 
   <div class="form-group js-category-tags-group">
@@ -116,10 +117,11 @@
         Select a tag set first.
       </span>
     </span>
+
     <%= f.select :topic_tag_ids, options_for_select(@category.topic_tags.map { |t| [t.name, t.id] },
                                                        selected: @category.topic_tags.pluck(:name)),
                  { include_blank: true }, multiple: true, class: 'form-element js-tag-select',
-                 data: { tag_set: @category.tag_set&.id, create: 'false' } %>
+                 data: { tag_set: @category.tag_set&.id, create: 'false', use_ids: 'true' }, disabled: disabled %>
   </div>
 
   <%= f.submit 'Save', class: 'button is-filled' %>
diff --git a/db/schema.rb b/db/schema.rb
index 915d9fbd6bca8789079b1948807197aa515f5eb7..ae7e6d69558fecd931424e957e98c2429ce2cc8e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 2020_05_08_112958) do
+ActiveRecord::Schema.define(version: 2020_05_08_115752) do
 
   create_table "active_storage_attachments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t|
     t.string "name", null: false
@@ -61,6 +61,16 @@ ActiveRecord::Schema.define(version: 2020_05_08_112958) do
     t.bigint "post_type_id", null: false
   end
 
+  create_table "categories_required_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t|
+    t.bigint "category_id"
+    t.bigint "tag_id"
+  end
+
+  create_table "categories_topic_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t|
+    t.bigint "category_id"
+    t.bigint "tag_id"
+  end
+
   create_table "close_reasons", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t|
     t.string "name"
     t.text "description"