Index: /trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 15666)
+++ /trunk/src/org/openstreetmap/josm/data/validation/tests/TagChecker.java	(revision 15667)
@@ -23,4 +23,5 @@
 import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 
 import javax.swing.JCheckBox;
@@ -35,4 +36,5 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.osm.TagMap;
 import org.openstreetmap.josm.data.osm.Tagged;
 import org.openstreetmap.josm.data.preferences.sources.ValidatorPrefHelper;
@@ -615,7 +617,23 @@
 
         if (checkPresetsTypes) {
-            for (TaggingPreset tp : TaggingPresets.getMatchingPresets(null, p.getKeys(), false)) {
-                TaggingPresetType presetType = TaggingPresetType.forPrimitive(p);
-                if (!tp.typeMatches(EnumSet.of(presetType))) {
+            TagMap tags = p.getKeys();
+            TaggingPresetType presetType = TaggingPresetType.forPrimitive(p);
+            EnumSet<TaggingPresetType> presetTypes = EnumSet.of(presetType);
+            Collection<TaggingPreset> matchingPresets = TaggingPresets.getMatchingPresets(null, tags, false);
+            Collection<TaggingPreset> matchingPresetsOK = matchingPresets.stream().filter(
+                    tp -> tp.typeMatches(presetTypes)).collect(Collectors.toList());
+            Collection<TaggingPreset> matchingPresetsKO = matchingPresets.stream().filter(
+                    tp -> !tp.typeMatches(presetTypes)).collect(Collectors.toList());
+
+            for (TaggingPreset tp : matchingPresetsKO) {
+                // Potential error, unless matching tags are all known by a supported preset
+                Map<String, String> matchingTags = tp.data.stream()
+                    .filter(i -> Boolean.TRUE.equals(i.matches(tags)))
+                    .filter(i -> i instanceof KeyedItem).map(i -> ((KeyedItem) i).key)
+                    .collect(Collectors.toMap(k -> k, tags::get));
+                if (matchingPresetsOK.stream().noneMatch(
+                        tp2 -> matchingTags.entrySet().stream().allMatch(
+                                e -> tp2.data.stream().anyMatch(
+                                        i -> i instanceof KeyedItem && ((KeyedItem) i).key.equals(e.getKey()))))) {
                     errors.add(TestError.builder(this, Severity.OTHER, INVALID_PRESETS_TYPE)
                             .message(tr("Object type not in preset"),
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java	(revision 15666)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/presets/TaggingPresetItem.java	(revision 15667)
@@ -76,5 +76,5 @@
      * @return {@code true} if matches (positive), {@code null} if neutral, {@code false} if mismatches (negative).
      */
-    protected Boolean matches(Map<String, String> tags) {
+    public Boolean matches(Map<String, String> tags) {
         return null;
     }
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/CheckGroup.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/CheckGroup.java	(revision 15666)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/CheckGroup.java	(revision 15667)
@@ -53,5 +53,5 @@
 
     @Override
-    protected Boolean matches(Map<String, String> tags) {
+    public Boolean matches(Map<String, String> tags) {
         for (Check check : checks) {
             if (Boolean.TRUE.equals(check.matches(tags))) {
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java	(revision 15666)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/presets/items/KeyedItem.java	(revision 15667)
@@ -191,5 +191,5 @@
 
     @Override
-    protected Boolean matches(Map<String, String> tags) {
+    public Boolean matches(Map<String, String> tags) {
         switch (MatchType.ofString(match)) {
         case NONE:
Index: /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java	(revision 15666)
+++ /trunk/test/unit/org/openstreetmap/josm/data/validation/tests/TagCheckerTest.java	(revision 15667)
@@ -336,3 +336,16 @@
         assertFalse(TagChecker.containsUnusualUnicodeCharacter("name", "Hökumət Evi"));
     }
+
+    /**
+     * Detects objects with types not supported by their presets.
+     * @throws IOException in case of I/O error
+     */
+    @Test
+    public void testObjectTypeNotSupportedByPreset() throws IOException {
+        List<TestError> errors = test(OsmUtils.createPrimitive("relation waterway=river"));
+        assertEquals(1, errors.size());
+        assertEquals(TagChecker.INVALID_PRESETS_TYPE, errors.get(0).getCode());
+        errors = test(OsmUtils.createPrimitive("relation type=waterway waterway=river"));
+        assertTrue(errors.toString(), errors.isEmpty());
+    }
 }
