Index: src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 14586)
+++ src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(working copy)
@@ -74,6 +74,9 @@
     private static final Map<String, String> harmonizedKeys = new HashMap<>();
     /** The spell check preset values which are not stored in TaggingPresets */
     private static volatile MultiMap<String, String> additionalPresetsValueData;
+    /** The spell check preset values which are not stored in TaggingPresets */
+    private static volatile MultiMap<String, String> oftenUsedValueData = new MultiMap<>();
+
     /** The TagChecker data */
     private static final List<CheckerData> checkerData = new ArrayList<>();
     private static final List<String> ignoreDataStartsWith = new ArrayList<>();
@@ -240,7 +243,9 @@
                             ignoreDataEndsWith.add(line);
                             break;
                         case "K:":
-                            ignoreDataTag.add(Tag.ofString(line));
+                            Tag tag = Tag.ofString(line);
+                            ignoreDataTag.add(tag);
+                            oftenUsedValueData.put(tag.getKey(), tag.getValue());
                             break;
                         default:
                             if (!key.startsWith(";")) {
@@ -531,86 +536,100 @@
                         withErrors.put(p, "UPK");
                     }
                 } else if (!isTagInPresets(key, value)) {
-                    // try to fix common typos and check again if value is still unknown
-                    final String harmonizedValue = harmonizeValue(prop.getValue());
-                    String fixedValue = null;
-                    Set<String> possibleValues = getPresetValues(key);
-                    List<String> fixVals = new ArrayList<>();
-                    int maxPresetValueLen = 0;
-                    if (possibleValues.contains(harmonizedValue)) {
-                        fixedValue = harmonizedValue;
-                    } else {
-                        // use Levenshtein distance to find typical typos
-                        int minDist = MAX_LEVENSHTEIN_DISTANCE + 1;
-                        String closest = null;
-                        for (String possibleVal : possibleValues) {
-                            if (possibleVal.isEmpty())
-                                continue;
-                            maxPresetValueLen = Math.max(maxPresetValueLen, possibleVal.length());
-                            if (harmonizedValue.length() < 3 && possibleVal.length() >= harmonizedValue.length() + MAX_LEVENSHTEIN_DISTANCE) {
-                                // don't suggest fix value when given value is short and lengths are too different
-                                // for example surface=u would result in surface=mud
-                                continue;
-                            }
-                            int dist = Utils.getLevenshteinDistance(possibleVal, harmonizedValue);
-                            if (dist >= harmonizedValue.length()) {
-                                // short value, all characters are different. Don't warn, might say Value '10' for key 'fee' looks like 'no'.
-                                continue;
-                            }
-                            if (dist < minDist) {
-                                closest = possibleVal;
-                                minDist = dist;
-                                fixVals.clear();
-                                fixVals.add(possibleVal);
-                            } else if (dist == minDist) {
-                                fixVals.add(possibleVal);
-                            }
-                        }
-                        if (minDist <= MAX_LEVENSHTEIN_DISTANCE && maxPresetValueLen > MAX_LEVENSHTEIN_DISTANCE
-                                && (harmonizedValue.length() > 3 || minDist < MAX_LEVENSHTEIN_DISTANCE)) {
-                            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_NO_FIX)
-                                        .message(tr("Misspelled property value"),
-                                                marktr("Value ''{0}'' for key ''{1}'' looks like one of {2}."),
-                                                prop.getValue(), key, fixVals)
-                                        .primitives(p).build());
-                                withErrors.put(p, "WPV");
-                                continue;
-                            }
-                        }
+                    tryGuess(p, key, value, withErrors);
+                }
+            }
+            if (checkFixmes && key != null && value != null && !value.isEmpty() && isFixme(key, value) && !withErrors.contains(p, "FIXME")) {
+                errors.add(TestError.builder(this, Severity.OTHER, FIXME)
+                        .message(tr("FIXMES"))
+                        .primitives(p)
+                        .build());
+                withErrors.put(p, "FIXME");
+            }
+        }
+    }
+
+    private void tryGuess(OsmPrimitive p, String key, String value, MultiMap<OsmPrimitive, String> withErrors) {
+        // try to fix common typos and check again if value is still unknown
+        final String harmonizedValue = harmonizeValue(value);
+        String fixedValue = null;
+        List<String> fixVals = new ArrayList<>();
+        int maxPresetValueLen = 0;
+        Set<String> presetValues = getPresetValues(key);
+        Set<String> oftenUsedValues = oftenUsedValueData.get(key);
+        for (Set<String> possibleValues: Arrays.asList(presetValues, oftenUsedValues)) {
+            if (possibleValues != null && possibleValues.contains(harmonizedValue)) {
+                fixedValue = harmonizedValue;
+                break;
+            }
+        }
+        if (fixedValue == null) {
+            // use Levenshtein distance to find typical typos
+            int minDist = MAX_LEVENSHTEIN_DISTANCE + 1;
+            String closest = null;
+            for (Set<String> possibleValues: Arrays.asList(presetValues, oftenUsedValues)) {
+                if (possibleValues == null)
+                    continue;
+                for (String possibleVal : possibleValues) {
+                    if (possibleVal.isEmpty())
+                        continue;
+                    maxPresetValueLen = Math.max(maxPresetValueLen, possibleVal.length());
+                    if (harmonizedValue.length() < 3 && possibleVal.length() >= harmonizedValue.length() + MAX_LEVENSHTEIN_DISTANCE) {
+                        // don't suggest fix value when given value is short and lengths are too different
+                        // for example surface=u would result in surface=mud
+                        continue;
                     }
-                    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"),
-                                        marktr("Value ''{0}'' for key ''{1}'' looks like ''{2}''."), prop.getValue(), key, newValue)
-                                .primitives(p)
-                                .build());
-                        withErrors.put(p, "WPV");
-                    } else {
-                        // unknown preset value
-                        errors.add(TestError.builder(this, Severity.OTHER, INVALID_VALUE)
-                                .message(tr("Presets do not contain property value"),
-                                        marktr("Value ''{0}'' for key ''{1}'' not in presets."), prop.getValue(), key)
-                                .primitives(p)
-                                .build());
-                        withErrors.put(p, "UPV");
+                    int dist = Utils.getLevenshteinDistance(possibleVal, harmonizedValue);
+                    if (dist >= harmonizedValue.length()) {
+                        // short value, all characters are different. Don't warn, might say Value '10' for key 'fee' looks like 'no'.
+                        continue;
                     }
+                    if (dist < minDist) {
+                        closest = possibleVal;
+                        minDist = dist;
+                        fixVals.clear();
+                        fixVals.add(possibleVal);
+                    } else if (dist == minDist) {
+                        fixVals.add(possibleVal);
+                    }
                 }
             }
-            if (checkFixmes && key != null && value != null && !value.isEmpty() && isFixme(key, value) && !withErrors.contains(p, "FIXME")) {
-               errors.add(TestError.builder(this, Severity.OTHER, FIXME)
-                .message(tr("FIXMES"))
-                .primitives(p)
-                .build());
-               withErrors.put(p, "FIXME");
+
+            if (minDist <= MAX_LEVENSHTEIN_DISTANCE && maxPresetValueLen > MAX_LEVENSHTEIN_DISTANCE
+                    && (harmonizedValue.length() > 3 || minDist < MAX_LEVENSHTEIN_DISTANCE)) {
+                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_NO_FIX)
+                            .message(tr("Unknown property value"),
+                                    marktr("Value ''{0}'' for key ''{1}'' is not in the presets, maybe one of {2} is meant?"),
+                                    value, key, fixVals)
+                            .primitives(p).build());
+                    withErrors.put(p, "WPV");
+                    return;
+                }
             }
         }
+        if (fixedValue != null) {
+            final String newValue = fixedValue;
+            // misspelled preset value
+            errors.add(TestError.builder(this, Severity.WARNING, MISSPELLED_VALUE)
+                    .message(tr("Unknown property value"),
+                            marktr("Value ''{0}'' for key ''{1}'' is not in the presets, maybe ''{2}'' is meant?"), value, key, newValue)
+                    .primitives(p)
+                    .build());
+            withErrors.put(p, "WPV");
+        } else {
+            // unknown preset value
+            errors.add(TestError.builder(this, Severity.OTHER, INVALID_VALUE)
+                    .message(tr("Presets do not contain property value"),
+                            marktr("Value ''{0}'' for key ''{1}'' not in presets."), value, key)
+                    .primitives(p)
+                    .build());
+            withErrors.put(p, "UPV");
+        }
     }
 
     private static boolean isFixme(String key, String value) {
Index: test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java
===================================================================
--- test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java	(revision 14586)
+++ test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java	(working copy)
@@ -104,8 +104,8 @@
     public void testMisspelledTag() throws IOException {
         final List<TestError> errors = test(OsmUtils.createPrimitive("node landuse=forrest"));
         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("Unknown property value", errors.get(0).getMessage());
+        assertEquals("Value 'forrest' for key 'landuse' is not in the presets, maybe 'forest' is meant?", errors.get(0).getDescription());
         assertEquals(Severity.WARNING, errors.get(0).getSeverity());
         assertFalse(errors.get(0).isFixable());
     }
@@ -118,8 +118,10 @@
     public void testMisspelledTag2() throws IOException {
         final List<TestError> errors = test(OsmUtils.createPrimitive("node highway=servics"));
         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("Unknown property value", errors.get(0).getMessage());
+        assertEquals(
+                "Value 'servics' for key 'highway' is not in the presets, maybe one of [service, services] is meant?",
+                errors.get(0).getDescription());
         assertEquals(Severity.WARNING, errors.get(0).getSeverity());
         assertFalse(errors.get(0).isFixable());
     }
@@ -132,8 +134,9 @@
     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("Unknown property value", errors.get(0).getMessage());
+        assertEquals("Value 'residentail' for key 'highway' is not in the presets, maybe 'residential' is meant?",
+                errors.get(0).getDescription());
         assertEquals(Severity.WARNING, errors.get(0).getSeverity());
         assertFalse(errors.get(0).isFixable());
     }
@@ -204,8 +207,9 @@
     public void testValueDifferentCase() throws IOException {
         final List<TestError> errors = test(OsmUtils.createPrimitive("node highway=Residential"));
         assertEquals(1, errors.size());
-        assertEquals("Misspelled property value", errors.get(0).getMessage());
-        assertEquals("Value 'Residential' for key 'highway' looks like 'residential'.", errors.get(0).getDescription());
+        assertEquals("Unknown property value", errors.get(0).getMessage());
+        assertEquals("Value 'Residential' for key 'highway' is not in the presets, maybe 'residential' is meant?",
+                errors.get(0).getDescription());
         assertEquals(Severity.WARNING, errors.get(0).getSeverity());
         assertFalse(errors.get(0).isFixable());
     }
