Index: src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 14500)
+++ src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(working copy)
@@ -13,6 +13,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -76,7 +77,7 @@
     /** The TagChecker data */
     private static final List<CheckerData> checkerData = new ArrayList<>();
     private static final List<String> ignoreDataStartsWith = new ArrayList<>();
-    private static final List<String> ignoreDataEquals = new ArrayList<>();
+    private static final Set<String> ignoreDataEquals = new HashSet<>();
     private static final List<String> ignoreDataEndsWith = new ArrayList<>();
     private static final List<Tag> ignoreDataTag = new ArrayList<>();
 
@@ -141,20 +142,23 @@
     protected JCheckBox prefCheckPaintBeforeUpload;
 
     // CHECKSTYLE.OFF: SingleSpaceSeparator
-    protected static final int EMPTY_VALUES      = 1200;
-    protected static final int INVALID_KEY       = 1201;
-    protected static final int INVALID_VALUE     = 1202;
-    protected static final int FIXME             = 1203;
-    protected static final int INVALID_SPACE     = 1204;
-    protected static final int INVALID_KEY_SPACE = 1205;
-    protected static final int INVALID_HTML      = 1206; /* 1207 was PAINT */
-    protected static final int LONG_VALUE        = 1208;
-    protected static final int LONG_KEY          = 1209;
-    protected static final int LOW_CHAR_VALUE    = 1210;
-    protected static final int LOW_CHAR_KEY      = 1211;
-    protected static final int MISSPELLED_VALUE  = 1212;
-    protected static final int MISSPELLED_KEY    = 1213;
-    protected static final int MULTIPLE_SPACES   = 1214;
+    protected static final int EMPTY_VALUES             = 1200;
+    protected static final int INVALID_KEY              = 1201;
+    protected static final int INVALID_VALUE            = 1202;
+    protected static final int FIXME                    = 1203;
+    protected static final int INVALID_SPACE            = 1204;
+    protected static final int INVALID_KEY_SPACE        = 1205;
+    protected static final int INVALID_HTML             = 1206; /* 1207 was PAINT */
+    protected static final int LONG_VALUE               = 1208;
+    protected static final int LONG_KEY                 = 1209;
+    protected static final int LOW_CHAR_VALUE           = 1210;
+    protected static final int LOW_CHAR_KEY             = 1211;
+    protected static final int MISSPELLED_VALUE         = 1212;
+    protected static final int MISSPELLED_KEY           = 1213;
+    protected static final int MULTIPLE_SPACES          = 1214;
+    protected static final int TRUNCATED_VALUE          = 1215;
+    protected static final int MISSPELLED_VALUE_NO_FIX  = 1216;
+    protected static final int TRUNCATED_VALUE_NO_FIX   = 1217;
     // CHECKSTYLE.ON: SingleSpaceSeparator
     // 1250 and up is used by tagcheck
 
@@ -387,33 +391,28 @@
      * @since 9023
      */
     public static boolean isTagIgnored(String key, String value) {
-        boolean tagInPresets = isTagInPresets(key, value);
-        boolean ignore = false;
-
+        if (ignoreDataEquals.contains(key)) {
+            return true;
+        }
         for (String a : ignoreDataStartsWith) {
             if (key.startsWith(a)) {
-                ignore = true;
+                return true;
             }
         }
-        for (String a : ignoreDataEquals) {
-            if (key.equals(a)) {
-                ignore = true;
-            }
-        }
         for (String a : ignoreDataEndsWith) {
             if (key.endsWith(a)) {
-                ignore = true;
+                return true;
             }
         }
 
-        if (!tagInPresets) {
+        if (!isTagInPresets(key, value)) {
             for (Tag a : ignoreDataTag) {
                 if (key.equals(a.getKey()) && value.equals(a.getValue())) {
-                    ignore = true;
+                    return true;
                 }
             }
         }
-        return ignore;
+        return false;
     }
 
     /**
@@ -534,12 +533,17 @@
                 } else if (!isTagInPresets(key, value)) {
                     // try to fix common typos and check again if value is still unknown
                     String fixedValue = harmonizeValue(prop.getValue());
-                    Map<String, String> possibleValues = getPossibleValues(getPresetValues(key));
+                    Set<String> possibleValues = getPresetValues(key);
                     List<String> fixVals = new ArrayList<>();
-                    if (!possibleValues.containsKey(fixedValue)) {
-                        int minDist = 2;
+                    List<String> sameStartVals = new ArrayList<>();
+                    if (!possibleValues.contains(fixedValue)) {
+                        int minDist = 10;
                         String closest = null;
-                        for (String possibleVal : possibleValues.keySet()) {
+                        for (String possibleVal : possibleValues) {
+                            if (possibleVal.isEmpty())
+                                continue;
+                            if (possibleVal.startsWith(fixedValue))
+                                sameStartVals.add(possibleVal);
                             int dist = Utils.getLevenshteinDistance(possibleVal, fixedValue);
                             if (dist < minDist) {
                                 closest = possibleVal;
@@ -550,13 +554,14 @@
                                 fixVals.add(possibleVal);
                             }
                         }
-                        if (minDist <= 1) {
+                        fixedValue = null;
+                        if (minDist <= 2) {
                             if (fixVals.size() < 2) {
                                 fixedValue = closest;
                             } else {
                                 Collections.sort(fixVals);
                                 // misspelled preset value with multiple good alternatives
-                                errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE)
+                                errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE_NO_FIX)
                                         .message(tr("Misspelled property value"),
                                                 marktr("Value ''{0}'' for key ''{1}'' looks like one of {2}."), prop.getValue(), key, fixVals)
                                         .primitives(p)
@@ -565,9 +570,23 @@
                                 continue;
                             }
                         }
+                        if (!sameStartVals.isEmpty()) {
+                            if (sameStartVals.size() == 1) {
+                                // only one preset value starts with the same characters
+                                fixedValue = sameStartVals.get(0);
+                            } else {
+                                errors.add(TestError.builder(this, Severity.WARNING, TRUNCATED_VALUE_NO_FIX)
+                                        .message(tr("Probably truncated property value"),
+                                                marktr("Value ''{0}'' for key ''{1}'' not in presets."),
+                                                prop.getValue(), key)
+                                        .primitives(p).build());
+                                withErrors.put(p, "WPV");
+                            }
+                            continue;
+                        }
                     }
-                    if (possibleValues.containsKey(fixedValue)) {
-                        final String newValue = possibleValues.get(fixedValue);
+                    if (fixedValue != null && possibleValues.contains(fixedValue)) {
+                        final String newValue = fixedValue;
                         // misspelled preset value
                         errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE)
                                 .message(tr("Misspelled property value"),
@@ -602,20 +621,6 @@
           || value.toLowerCase(Locale.ENGLISH).contains("fixme") || value.contains("check and delete");
     }
 
-    private static Map<String, String> getPossibleValues(Set<String> values) {
-        // generate a map with common typos
-        Map<String, String> map = new HashMap<>();
-        if (values != null) {
-            for (String value : values) {
-                map.put(value, value);
-                if (value.contains("_")) {
-                    map.put(value.replace("_", ""), value);
-                }
-            }
-        }
-        return map;
-    }
-
     private static String harmonizeKey(String key) {
         return Utils.strip(key.toLowerCase(Locale.ENGLISH).replace('-', '_').replace(':', '_').replace(' ', '_'), "-_;:,");
     }
@@ -778,7 +783,7 @@
             int code = testError.getCode();
             return code == INVALID_KEY || code == EMPTY_VALUES || code == INVALID_SPACE ||
                    code == INVALID_KEY_SPACE || code == INVALID_HTML || code == MISSPELLED_VALUE ||
-                   code == MULTIPLE_SPACES;
+                   code == MULTIPLE_SPACES || code == TRUNCATED_VALUE;
         }
 
         return false;
Index: test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java	(revision 14500)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java	(working copy)
@@ -15,6 +15,7 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.validation.Severity;
 import org.openstreetmap.josm.data.validation.TestError;
 import org.openstreetmap.josm.testutils.JOSMTestRules;
 
@@ -77,6 +78,7 @@
         assertEquals(1, errors.size());
         assertEquals("Misspelled property key", errors.get(0).getMessage());
         assertEquals("Key 'Brand' looks like 'brand'.", errors.get(0).getDescription());
+        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
         assertFalse(errors.get(0).isFixable());
     }
 
@@ -90,6 +92,8 @@
         assertEquals(1, errors.size());
         assertEquals("Presets do not contain property key", errors.get(0).getMessage());
         assertEquals("Key 'namez' not in presets.", errors.get(0).getDescription());
+        assertEquals(Severity.OTHER, errors.get(0).getSeverity());
+        assertFalse(errors.get(0).isFixable());
     }
 
     /**
@@ -102,6 +106,8 @@
         assertEquals(1, errors.size());
         assertEquals("Misspelled property value", errors.get(0).getMessage());
         assertEquals("Value 'forrest' for key 'landuse' looks like 'forest'.", errors.get(0).getDescription());
+        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
+        assertTrue(errors.get(0).isFixable());
     }
 
     /**
@@ -114,9 +120,39 @@
         assertEquals(1, errors.size());
         assertEquals("Misspelled property value", errors.get(0).getMessage());
         assertEquals("Value 'servics' for key 'highway' looks like one of [service, services].", errors.get(0).getDescription());
+        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
+        assertFalse(errors.get(0).isFixable());
     }
 
     /**
+     * Check for misspelled value.
+     * @throws IOException if any I/O error occurs
+     */
+    @Test
+    public void testMisspelledTag3() throws IOException {
+        final List<TestError> errors = test(OsmUtils.createPrimitive("node highway=residentail"));
+        assertEquals(1, errors.size());
+        assertEquals("Misspelled property value", errors.get(0).getMessage());
+        assertEquals("Value 'residentail' for key 'highway' looks like 'residential'.", errors.get(0).getDescription());
+        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
+        assertTrue(errors.get(0).isFixable());
+    }
+
+    /**
+     * Check for misspelled value.
+     * @throws IOException if any I/O error occurs
+     */
+    @Test
+    public void testMisspelledTag4() throws IOException {
+        final List<TestError> errors = test(OsmUtils.createPrimitive("node highway=res"));
+        assertEquals(1, errors.size());
+        assertEquals("Probably truncated property value", errors.get(0).getMessage());
+        assertEquals("Value 'res' for key 'highway' not in presets.", errors.get(0).getDescription());
+        assertEquals(Severity.WARNING, errors.get(0).getSeverity());
+        assertFalse(errors.get(0).isFixable());
+    }
+
+    /**
      * Checks that tags specifically ignored are effectively not in internal presets.
      * @throws IOException if any I/O error occurs
      */
