diff --git a/src/core/fixtures/anhalter.json b/src/core/fixtures/anhalter.json
index 2d1840f5cf031ad8fee2864762e77a99d15312e7..4b2e4914e16b37045f4948a51633d2353280de81 100644
--- a/src/core/fixtures/anhalter.json
+++ b/src/core/fixtures/anhalter.json
@@ -74,6 +74,28 @@
         "model": "core.conferencetag",
         "pk": 3
     },
+    {
+        "fields": {
+            "conference": "017c0749-a2ea-4f86-92cd-e60b4508dd98",
+            "slug": "guter Geschmack",
+            "value_type": "boolean",
+            "is_public": true,
+            "description": null
+        },
+        "model": "core.conferencetag",
+        "pk": 4
+    },
+    {
+        "fields": {
+            "conference": "017c0749-a2ea-4f86-92cd-e60b4508dd98",
+            "slug": "Autor des besten Gedichts",
+            "value_type": "string",
+            "is_public": true,
+            "description": null
+        },
+        "model": "core.conferencetag",
+        "pk": 5
+    },
     {
         "fields": {
             "conference": "017c0749-a2ea-4f86-92cd-e60b4508dd98",
@@ -164,4 +186,4 @@
         "model": "core.event",
         "pk": "35e10dfc-11c2-475b-b682-da1ddd291770"
     }
-]
\ No newline at end of file
+]
diff --git a/src/core/models/tags.py b/src/core/models/tags.py
index 96368d7c2a7779c9384a83f48edab681b3c7bbab..c2d7272009ea5c91966e103302845d2cbaddf0b7 100644
--- a/src/core/models/tags.py
+++ b/src/core/models/tags.py
@@ -66,7 +66,7 @@ class TagItem(models.Model):
             return self._value_int == 0
 
     @value.setter
-    def _set_value(self, new_value):
+    def value(self, new_value):
         self.set_value(new_value)
 
     def set_value(self, new_value):
diff --git a/src/core/tests/tags.py b/src/core/tests/tags.py
index 30f196a3239ddf2bf9c0393af87b65a7447451d4..cad9f4da24b0379bb336f4548c8b7a7f8dd51536 100644
--- a/src/core/tests/tags.py
+++ b/src/core/tests/tags.py
@@ -1,10 +1,11 @@
 from django.contrib.auth.models import AnonymousUser
+from django.contrib.contenttypes.models import ContentType
 from django.test import TestCase
 
 from ..models.assemblies import Assembly
 from ..models.conference import Conference
 from ..models.events import Event
-from ..models.tags import ConferenceTag, TaggedItemMixin
+from ..models.tags import ConferenceTag, TaggedItemMixin, TagItem
 
 
 class TaggingTests(TestCase):
@@ -90,3 +91,127 @@ class TaggingTests(TestCase):
     def testAssemblyTagging(self):
         assembly = Assembly.objects.filter(conference=self.conference).first()
         self._testTagManagement(assembly)
+
+
+class TagItemTests(TestCase):
+    fixtures = ['anhalter.json']
+
+    def setUp(self):
+        self.conference = Conference.objects.get(slug='vogc')
+        self.user = AnonymousUser()
+        self.event = Event.objects.filter(conference=self.conference).first()
+        self.tag_items = self._createTagItems()
+
+    def _createTagItem(self, tag_slug:str) -> TagItem:
+        tag = ConferenceTag.objects.get(conference=self.conference, slug=tag_slug)
+        return TagItem(tag=tag, target_type=ContentType.objects.get_for_model(type(self.event)), target_id=self.event.id)
+
+    def _createTagItems(self):
+        result = {}
+        for tag_slug in ['foo', 'bar', 'michelinstars', 'guter Geschmack', 'Autor des besten Gedichts']:
+            result[tag_slug] = self._createTagItem(tag_slug)
+
+        return result
+
+    def _validate_value_type(self, tag_item: TagItem):
+        value_type = tag_item.tag.value_type
+        value = tag_item.value
+        if value is None:
+            return
+        if value_type == ConferenceTag.Type.SIMPLE:
+            self.fail("Simple tag item did not return None as value")
+        if value_type == ConferenceTag.Type.STRING:
+            self.assertTrue(isinstance(value, str), "String tag item did not return None or a string as value")
+        if value_type == ConferenceTag.Type.INT:
+            self.assertTrue(isinstance(value, int), "Int tag item did not return None or an int as value")
+        if value_type == ConferenceTag.Type.BOOL:
+            self.assertTrue(isinstance(value, bool), "Bool tag item did not return None or a bool as value")
+
+    def test_get_value_check_type_uninitialized(self):
+        for tag_item in self.tag_items.values():
+            self._validate_value_type(tag_item)
+
+    def test_get_value_check_type_after_set(self):
+        for tag_item in self.tag_items.values():
+            value_type = tag_item.tag.value_type
+            if value_type == ConferenceTag.Type.STRING:
+                tag_item.value = "Test"
+            if value_type == ConferenceTag.Type.INT:
+                tag_item.value = 42
+            if value_type == ConferenceTag.Type.BOOL:
+                tag_item.value = True
+            self._validate_value_type(tag_item)
+
+    def test_value_check_get_after_set_intended(self):
+        for tag_item in self.tag_items.values():
+            value_type = tag_item.tag.value_type
+            value = None
+            if value_type == ConferenceTag.Type.STRING:
+                value = "Test"
+            if value_type == ConferenceTag.Type.INT:
+                value = 42
+            if value_type == ConferenceTag.Type.BOOL:
+                value = True
+            tag_item.value = value
+            self.assertEqual(tag_item.value, value)
+
+    def test_value_check_boolean_coerce(self):
+        tag = self.tag_items["guter Geschmack"]
+        for v in [False, 0, 'n', 'no', 'nein', 'false', 'off']:
+            tag.value = True
+            self.assertTrue(tag.value)
+            tag.value = v
+            self.assertFalse(tag.value, "Value {} did not yield false".format(v))
+
+        for v in [True, -2, -1, 1, 2, 3, 'y', 'j', 'yes', 'ja', 'true', 'on']:
+            tag.value = False
+            self.assertFalse(tag.value)
+            tag.value = v
+            self.assertTrue(tag.value, "Value {} did not yield true".format(v))
+
+    def test_value_set_check_simple_with_wrong_argument(self):
+        tag = self.tag_items["foo"]
+        with self.assertRaises(ValueError):
+            tag.value = self.user
+        with self.assertRaises(ValueError):
+            tag.value = "Test"
+        with self.assertRaises(ValueError):
+            tag.value = 42
+        with self.assertRaises(ValueError):
+            tag.value = True
+
+    def test_value_set_check_string_with_wrong_argument(self):
+        tag = self.tag_items["Autor des besten Gedichts"]
+        with self.assertRaises(ValueError):
+            tag.value = None
+        with self.assertRaises(ValueError):
+            tag.value = self.user
+        with self.assertRaises(ValueError):
+            tag.value = 42
+        with self.assertRaises(ValueError):
+            tag.value = True
+
+    def test_value_set_check_int_with_wrong_argument(self):
+        tag = self.tag_items["michelinstars"]
+        with self.assertRaises(ValueError):
+            tag.value = None
+        with self.assertRaises(ValueError):
+            tag.value = self.user
+        with self.assertRaises(ValueError):
+            tag.value = "Test"
+        # Python coerces bool to int by itself
+
+    def test_value_set_check_bool_with_wrong_argument(self):
+        tag = self.tag_items["guter Geschmack"]
+        with self.assertRaises(ValueError):
+            tag.value = None
+        with self.assertRaises(ValueError):
+            tag.value = self.user
+        with self.assertRaises(ValueError):
+            tag.value = "Test"
+        with self.assertRaises(ValueError):
+            tag.value = "foo"
+        with self.assertRaises(ValueError):
+            tag.value = ""
+        with self.assertRaises(ValueError):
+            tag.value = "bar"