Index: src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 19021)
+++ src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(working copy)
@@ -70,6 +70,7 @@
 import org.openstreetmap.josm.gui.tagging.presets.items.KeyedItem;
 import org.openstreetmap.josm.gui.tagging.presets.items.PresetListEntry;
 import org.openstreetmap.josm.gui.tagging.presets.items.RegionSpecific;
+import org.openstreetmap.josm.gui.tagging.presets.items.Text;
 import org.openstreetmap.josm.gui.widgets.EditableList;
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.spi.preferences.Config;
@@ -111,6 +112,8 @@
     private static final List<Tag> ignoreDataTag = new ArrayList<>();
     /** tag keys that have only numerical values in the presets */
     private static final Set<String> ignoreForLevenshtein = new HashSet<>();
+    /** tag keys that have freeform text in the presets */
+    private static final Set<String> freeformKeys = new HashSet<>();
 
     /** tag keys that are allowed to be the same on a multipolygon and an outer way */
     private static final Set<String> ignoreForOuterMPSameTagCheck = new HashSet<>();
@@ -259,6 +262,15 @@
             if (allNumerical) {
                 ignoreForLevenshtein.add(key);
             }
+            // see #23571
+            boolean isfreeformKey = TaggingPresets.getTaggingPresets().stream()
+                    .anyMatch(preset -> preset.data.stream()
+                            .filter(KeyedItem.class::isInstance)
+                            .map(KeyedItem.class::cast)
+                            .anyMatch(item -> key.equals(item.key) && item instanceof Text));
+            if (isfreeformKey) {
+                freeformKeys.add(key);
+            }
         }
     }
 
@@ -280,6 +292,7 @@
         oftenUsedTags.clear();
         presetIndex.clear();
         ignoreForOuterMPSameTagCheck.clear();
+        freeformKeys.clear();
 
         StringBuilder errorSources = new StringBuilder();
         for (String source : Config.getPref().getList(PREF_SOURCES, DEFAULT_SOURCES)) {
@@ -1175,7 +1188,7 @@
                     .primitives(p)
                     .build());
             withErrors.put(p, "WPV");
-        } else if (includeOtherSeverity) {
+        } else if (includeOtherSeverity && !freeformKeys.contains(key)) {
             // unknown preset value
             errors.add(TestError.builder(this, Severity.OTHER, INVALID_VALUE)
                     .message(tr("Presets do not contain property value"),
