Index: /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 8491)
+++ /trunk/src/org/openstreetmap/josm/gui/preferences/SourceEditor.java	(revision 8492)
@@ -33,6 +33,6 @@
 import java.util.EventObject;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
@@ -1579,5 +1579,5 @@
          */
         public final Set<String> getActiveUrls() {
-            Set<String> urls = new HashSet<>();
+            Set<String> urls = new LinkedHashSet<>(); // retain order
             for (SourceEntry e : get()) {
                 if (e.active) {
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 8491)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 8492)
@@ -124,7 +124,14 @@
     }
 
+    /**
+     * Returns the translated name of this preset, prefixed with the group names it belongs to.
+     */
     public String getName() {
         return group != null ? group.getName() + "/" + getLocaleName() : getLocaleName();
     }
+
+    /**
+     * Returns the non translated name of this preset, prefixed with the (non translated) group names it belongs to.
+     */
     public String getRawName() {
         return group != null ? group.getRawName() + "/" + name : name;
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java	(revision 8491)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetMenu.java	(revision 8492)
@@ -13,4 +13,5 @@
 import java.util.Comparator;
 import java.util.List;
+import java.util.Objects;
 
 import javax.swing.Action;
@@ -36,4 +37,20 @@
                 return AlphanumComparator.getInstance().compare(o1.getText(), o2.getText());
         }
+    }
+
+    /**
+     * {@code TaggingPresetMenu} are considered equivalent if (and only if) their {@link #getRawName()} match.
+     */
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        TaggingPresetMenu that = (TaggingPresetMenu) o;
+        return Objects.equals(getRawName(), that.getRawName());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getRawName());
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetReader.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetReader.java	(revision 8491)
+++ /trunk/src/org/openstreetmap/josm/gui/tagging/TaggingPresetReader.java	(revision 8492)
@@ -16,4 +16,5 @@
 import java.util.HashMap;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -27,4 +28,6 @@
 import org.openstreetmap.josm.io.CachedFile;
 import org.openstreetmap.josm.io.UTFInputStreamReader;
+import org.openstreetmap.josm.tools.Predicates;
+import org.openstreetmap.josm.tools.Utils;
 import org.openstreetmap.josm.tools.XmlObjectParser;
 import org.xml.sax.SAXException;
@@ -97,4 +100,21 @@
     }
 
+    static class HashSetWithLast<E> extends LinkedHashSet<E> {
+        protected E last = null;
+
+        @Override
+        public boolean add(E e) {
+            last = e;
+            return super.add(e);
+        }
+
+        /**
+         * Returns the last inserted element.
+         */
+        public E getLast() {
+            return last;
+        }
+    }
+
     /**
      * Reads all tagging presets from the input reader.
@@ -105,8 +125,22 @@
      */
     public static Collection<TaggingPreset> readAll(Reader in, boolean validate) throws SAXException {
+        return readAll(in, validate, new HashSetWithLast<TaggingPreset>());
+    }
+
+    /**
+     * Reads all tagging presets from the input reader.
+     * @param in The input reader
+     * @param validate if {@code true}, XML validation will be performed
+     * @param all the accumulator for parsed tagging presets
+     * @return the accumulator
+     * @throws SAXException if any XML error occurs
+     */
+    static Collection<TaggingPreset> readAll(Reader in, boolean validate, HashSetWithLast<TaggingPreset> all) throws SAXException {
         XmlObjectParser parser = buildParser();
 
-        Deque<TaggingPreset> all = new LinkedList<>();
+        /** to detect end of {@code <group>} */
         TaggingPresetMenu lastmenu = null;
+        /** to detect end of reused {@code <group>} */
+        TaggingPresetMenu lastmenuOriginal = null;
         TaggingPresetItems.Roles lastrole = null;
         final List<TaggingPresetItems.Check> checks = new LinkedList<>();
@@ -173,11 +207,18 @@
             if (o instanceof TaggingPresetMenu) {
                 TaggingPresetMenu tp = (TaggingPresetMenu) o;
-                if (tp == lastmenu) {
+                if (tp == lastmenu || tp == lastmenuOriginal) {
                     lastmenu = tp.group;
                 } else {
                     tp.group = lastmenu;
-                    tp.setDisplayName();
+                    if (all.contains(tp)) {
+                        lastmenuOriginal = tp;
+                        tp = (TaggingPresetMenu) Utils.filter(all, Predicates.<TaggingPreset>equalTo(tp)).iterator().next();
+                        lastmenuOriginal.group = null;
+                    } else {
+                        tp.setDisplayName();
+                        all.add(tp);
+                        lastmenuOriginal = null;
+                    }
                     lastmenu = tp;
-                    all.add(tp);
                 }
                 lastrole = null;
@@ -253,4 +294,17 @@
      */
     public static Collection<TaggingPreset> readAll(String source, boolean validate) throws SAXException, IOException {
+        return readAll(source, validate, new HashSetWithLast<TaggingPreset>());
+    }
+
+    /**
+     * Reads all tagging presets from the given source.
+     * @param source a given filename, URL or internal resource
+     * @param validate if {@code true}, XML validation will be performed
+     * @param all the accumulator for parsed tagging presets
+     * @return the accumulator
+     * @throws SAXException if any XML error occurs
+     * @throws IOException if any I/O error occurs
+     */
+    static Collection<TaggingPreset> readAll(String source, boolean validate, HashSetWithLast<TaggingPreset> all) throws SAXException, IOException {
         Collection<TaggingPreset> tp;
         CachedFile cf = new CachedFile(source).setHttpAccept(PRESET_MIME_TYPES);
@@ -263,5 +317,5 @@
             }
             try (InputStreamReader r = UTFInputStreamReader.create(zip == null ? cf.getInputStream() : zip)) {
-                tp = readAll(new BufferedReader(r), validate);
+                tp = readAll(new BufferedReader(r), validate, all);
             }
         }
@@ -287,8 +341,8 @@
      */
     public static Collection<TaggingPreset> readAll(Collection<String> sources, boolean validate, boolean displayErrMsg) {
-        List<TaggingPreset> allPresets = new LinkedList<>();
+        HashSetWithLast<TaggingPreset> allPresets = new HashSetWithLast<>();
         for(String source : sources)  {
             try {
-                allPresets.addAll(readAll(source, validate));
+                readAll(source, validate, allPresets);
             } catch (IOException e) {
                 Main.error(e, false);
