Index: src/org/openstreetmap/josm/Main.java
===================================================================
--- src/org/openstreetmap/josm/Main.java	(revision 9784)
+++ src/org/openstreetmap/josm/Main.java	(working copy)
@@ -14,6 +14,7 @@
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.io.File;
+import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -1097,6 +1098,11 @@
                     Main.main.removeLayer(l);
                 }
             }
+            try {
+                pref.saveDefaults();
+            } catch (IOException ex) {
+                Main.warn(tr("Failed to save default preferences."));
+            }
             worker.shutdownNow();
             ImageProvider.shutdown(true);
 
Index: src/org/openstreetmap/josm/data/Preferences.java
===================================================================
--- src/org/openstreetmap/josm/data/Preferences.java	(revision 9784)
+++ src/org/openstreetmap/josm/data/Preferences.java	(working copy)
@@ -65,8 +65,10 @@
 import org.openstreetmap.josm.io.XmlWriter;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
 import org.openstreetmap.josm.tools.ColorHelper;
+import org.openstreetmap.josm.tools.FilteredCollection;
 import org.openstreetmap.josm.tools.I18n;
 import org.openstreetmap.josm.tools.MultiMap;
+import org.openstreetmap.josm.tools.Predicate;
 import org.openstreetmap.josm.tools.Utils;
 import org.xml.sax.SAXException;
 
@@ -299,6 +301,10 @@
         return new File(getPreferencesDirectory(), "preferences.xml");
     }
 
+    public File getDefaultsCacheFile() {
+        return new File(getCacheDirectory(), "default_preferences.xml");
+    }
+
     /**
      * Returns the user plugin directory
      * @return The user plugin directory
@@ -487,17 +493,32 @@
         return put(key, Long.toString(value));
     }
 
+    private Predicate<Entry<String, Setting<?>>> NO_DEFAULT_SETTINGS_ENTRY = new Predicate<Entry<String, Setting<?>>>() {
+        @Override
+        public boolean evaluate(Entry<String, Setting<?>> e) {
+            return !e.getValue().equals(defaultsMap.get(e.getKey()));
+        }
+    };
+    
     /**
      * Called after every put. In case of a problem, do nothing but output the error in log.
      * @throws IOException if any I/O error occurs
      */
     public void save() throws IOException {
+        save(getPreferenceFile(),
+                new FilteredCollection<>(settingsMap.entrySet(), NO_DEFAULT_SETTINGS_ENTRY), false);
+    }
+    
+    public void saveDefaults() throws IOException {
+        save(getDefaultsCacheFile(), defaultsMap.entrySet(), true);
+    }
+    
+    public void save(File prefFile, Collection<Entry<String, Setting<?>>> settings, boolean nullValueAllowed) throws IOException {
         /* currently unused, but may help to fix configuration issues in future */
         putInteger("josm.version", Version.getInstance().getVersion());
 
         updateSystemProperties();
 
-        File prefFile = getPreferenceFile();
         File backupFile = new File(prefFile + "_backup");
 
         // Backup old preferences if there are old preferences
@@ -507,7 +528,7 @@
 
         try (PrintWriter out = new PrintWriter(new OutputStreamWriter(
                 new FileOutputStream(prefFile + "_tmp"), StandardCharsets.UTF_8), false)) {
-            out.print(toXML(settingsMap, false));
+            out.print(toXML(settings, false, nullValueAllowed));
         }
 
         File tmpFile = new File(prefFile + "_tmp");
@@ -552,6 +573,14 @@
         updateSystemProperties();
         removeObsolete(reader.getVersion());
     }
+    
+    protected void loadDefaults() throws IOException, XMLStreamException, SAXException {
+        File def = getDefaultsCacheFile();
+        PreferencesReader reader = new PreferencesReader();
+        reader.fromXML(def);
+        defaultsMap.clear();
+        defaultsMap.putAll(reader.getSettings());
+    }
 
     public void fromXML(Reader in) throws XMLStreamException {
         PreferencesReader reader = new PreferencesReader();
@@ -623,7 +652,7 @@
         try {
             load();
             initSuccessful = true;
-        } catch (Exception e) {
+        } catch (IOException | SAXException | XMLStreamException e) {
             Main.error(e);
             File backupFile = new File(prefDir, "preferences.xml.bak");
             JOptionPane.showMessageDialog(
@@ -643,6 +672,22 @@
                 Main.warn(tr("Failed to initialize preferences. Failed to reset preference file to default: {0}", getPreferenceFile()));
             }
         }
+        File def = getDefaultsCacheFile();
+        if (def.exists()) {
+            try {
+                loadDefaults();
+            } catch (IOException | XMLStreamException | SAXException e) {
+                Main.error(e);
+                Main.warn(tr("Failed to initialize defaults cache."));
+                try {
+                    defaultsMap.clear();
+                    saveDefaults();
+                } catch (IOException e1) {
+                    Main.error(e1);
+                    Main.warn(tr("Failed to initialize defaults cache."));
+                }
+            }
+        }
     }
 
     public final void resetToDefault() {
@@ -1327,11 +1372,13 @@
     private class SettingToXml implements SettingVisitor {
         private final StringBuilder b;
         private final boolean noPassword;
+        private final boolean nullValueAllowed;
         private String key;
 
-        SettingToXml(StringBuilder b, boolean noPassword) {
+        SettingToXml(StringBuilder b, boolean noPassword, boolean nullValueAllowed) {
             this.b = b;
             this.noPassword = noPassword;
+            this.nullValueAllowed = nullValueAllowed;
         }
 
         public void setKey(String key) {
@@ -1342,70 +1389,88 @@
         public void visit(StringSetting setting) {
             if (noPassword && "osm-server.password".equals(key))
                 return; // do not store plain password.
-            /* don't save default values */
-            if (setting.equals(defaultsMap.get(key)))
-                return;
             b.append("  <tag key='");
             b.append(XmlWriter.encode(key));
-            b.append("' value='");
-            b.append(XmlWriter.encode(setting.getValue()));
-            b.append("'/>\n");
+            if (setting.getValue() != null) {
+                b.append("' value='");
+                b.append(XmlWriter.encode(setting.getValue()));
+                b.append("'/>\n");
+            } else if (nullValueAllowed) {
+                b.append("' novalue='true'/>\n");
+            } else {
+                throw new NullPointerException();
+            }
         }
 
         @Override
         public void visit(ListSetting setting) {
-            /* don't save default values */
-            if (setting.equals(defaultsMap.get(key)))
-                return;
-            b.append("  <list key='").append(XmlWriter.encode(key)).append("'>\n");
-            for (String s : setting.getValue()) {
-                b.append("    <entry value='").append(XmlWriter.encode(s)).append("'/>\n");
+            b.append("  <list key='").append(XmlWriter.encode(key));
+            if (setting.getValue() != null) {
+                b.append("'>\n");
+                for (String s : setting.getValue()) {
+                    b.append("    <entry value='").append(XmlWriter.encode(s)).append("'/>\n");
+                }
+                b.append("  </list>\n");
+            } else if (nullValueAllowed) {
+                b.append("' novalue='true'/>\n");
+            } else {
+                throw new NullPointerException();
             }
-            b.append("  </list>\n");
         }
 
         @Override
         public void visit(ListListSetting setting) {
-            /* don't save default values */
-            if (setting.equals(defaultsMap.get(key)))
-                return;
-            b.append("  <lists key='").append(XmlWriter.encode(key)).append("'>\n");
-            for (List<String> list : setting.getValue()) {
-                b.append("    <list>\n");
-                for (String s : list) {
-                    b.append("      <entry value='").append(XmlWriter.encode(s)).append("'/>\n");
+            b.append("  <lists key='").append(XmlWriter.encode(key));
+            if (setting.getValue() != null) {
+                b.append("'>\n");
+                for (List<String> list : setting.getValue()) {
+                    b.append("    <list>\n");
+                    for (String s : list) {
+                        b.append("      <entry value='").append(XmlWriter.encode(s)).append("'/>\n");
+                    }
+                    b.append("    </list>\n");
                 }
-                b.append("    </list>\n");
+                b.append("  </lists>\n");
+            } else if (nullValueAllowed) {
+                b.append("' novalue='true'/>\n");
+            } else {
+                throw new NullPointerException();
             }
-            b.append("  </lists>\n");
         }
 
         @Override
         public void visit(MapListSetting setting) {
-            b.append("  <maps key='").append(XmlWriter.encode(key)).append("'>\n");
-            for (Map<String, String> struct : setting.getValue()) {
-                b.append("    <map>\n");
-                for (Entry<String, String> e : struct.entrySet()) {
-                    b.append("      <tag key='").append(XmlWriter.encode(e.getKey()))
-                     .append("' value='").append(XmlWriter.encode(e.getValue())).append("'/>\n");
+            b.append("  <maps key='").append(XmlWriter.encode(key));
+            if (setting.getValue() != null) {
+                b.append("'>\n");
+                for (Map<String, String> struct : setting.getValue()) {
+                    b.append("    <map>\n");
+                    for (Entry<String, String> e : struct.entrySet()) {
+                        b.append("      <tag key='").append(XmlWriter.encode(e.getKey()))
+                         .append("' value='").append(XmlWriter.encode(e.getValue())).append("'/>\n");
+                    }
+                    b.append("    </map>\n");
                 }
-                b.append("    </map>\n");
+                b.append("  </maps>\n");
+            } else if (nullValueAllowed) {
+                b.append("' novalue='true'/>\n");
+            } else {
+                throw new NullPointerException();
             }
-            b.append("  </maps>\n");
         }
     }
 
     public String toXML(boolean nopass) {
-        return toXML(settingsMap, nopass);
+        return toXML(settingsMap.entrySet(), nopass, false);
     }
 
-    public String toXML(Map<String, Setting<?>> settings, boolean nopass) {
+    public String toXML(Collection<Entry<String, Setting<?>>> settings, boolean nopass, boolean nullValueAllowed) {
         StringBuilder b = new StringBuilder(
                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<preferences xmlns=\"")
                 .append(Main.getXMLBase()).append("/preferences-1.0\" version=\"")
                 .append(Version.getInstance().getVersion()).append("\">\n");
-        SettingToXml toXml = new SettingToXml(b, nopass);
-        for (Entry<String, Setting<?>> e : settings.entrySet()) {
+        SettingToXml toXml = new SettingToXml(b, nopass, nullValueAllowed);
+        for (Entry<String, Setting<?>> e : settings) {
             toXml.setKey(e.getKey());
             e.getValue().visit(toXml);
         }
Index: src/org/openstreetmap/josm/data/preferences/PreferencesReader.java
===================================================================
--- src/org/openstreetmap/josm/data/preferences/PreferencesReader.java	(revision 9784)
+++ src/org/openstreetmap/josm/data/preferences/PreferencesReader.java	(working copy)
@@ -137,7 +137,11 @@
                 String localName = parser.getLocalName();
                 switch(localName) {
                 case "tag":
-                    settings.put(parser.getAttributeValue(null, "key"), new StringSetting(parser.getAttributeValue(null, "value")));
+                    if (parser.getAttributeValue(null, "novalue") != null) {
+                        settings.put(parser.getAttributeValue(null, "key"), new StringSetting(null));
+                    } else {
+                        settings.put(parser.getAttributeValue(null, "key"), new StringSetting(parser.getAttributeValue(null, "value")));
+                    }
                     jumpToEnd();
                     break;
                 case "list":
@@ -173,50 +177,69 @@
         List<String> entries = null;
         List<List<String>> lists = null;
         List<Map<String, String>> maps = null;
-        while (true) {
-            int event = parser.next();
-            if (event == XMLStreamConstants.START_ELEMENT) {
-                String localName = parser.getLocalName();
-                switch(localName) {
-                case "entry":
-                    if (entries == null) {
-                        entries = new ArrayList<>();
-                    }
-                    entries.add(parser.getAttributeValue(null, "value"));
-                    jumpToEnd();
+        if (parser.getAttributeValue(null, "novalue") != null) {
+            switch (name) {
+                case "lists":
+                    settings.put(key, new ListListSetting(null));
                     break;
-                case "list":
-                    if (lists == null) {
-                        lists = new ArrayList<>();
-                    }
-                    lists.add(parseInnerList());
+                case "maps":
+                    settings.put(key, new MapListSetting(null));
                     break;
-                case "map":
-                    if (maps == null) {
-                        maps = new ArrayList<>();
+                default:
+                    settings.put(key, new ListSetting(null));
+                    break;
+            }
+            jumpToEnd();
+        } else {
+            while (true) {
+                int event = parser.next();
+                if (event == XMLStreamConstants.START_ELEMENT) {
+                    String localName = parser.getLocalName();
+                    switch(localName) {
+                    case "entry":
+                        if (entries == null) {
+                            entries = new ArrayList<>();
+                        }
+                        entries.add(parser.getAttributeValue(null, "value"));
+                        jumpToEnd();
+                        break;
+                    case "list":
+                        if (lists == null) {
+                            lists = new ArrayList<>();
+                        }
+                        lists.add(parseInnerList());
+                        break;
+                    case "map":
+                        if (maps == null) {
+                            maps = new ArrayList<>();
+                        }
+                        maps.add(parseMap());
+                        break;
+                    default:
+                        throwException("Unexpected element: "+localName);
                     }
-                    maps.add(parseMap());
+                } else if (event == XMLStreamConstants.END_ELEMENT) {
                     break;
-                default:
-                    throwException("Unexpected element: "+localName);
                 }
-            } else if (event == XMLStreamConstants.END_ELEMENT) {
-                break;
             }
-        }
-        if (entries != null) {
-            settings.put(key, new ListSetting(Collections.unmodifiableList(entries)));
-        } else if (lists != null) {
-            settings.put(key, new ListListSetting(Collections.unmodifiableList(lists)));
-        } else if (maps != null) {
-            settings.put(key, new MapListSetting(Collections.unmodifiableList(maps)));
-        } else {
-            if ("lists".equals(name)) {
-                settings.put(key, new ListListSetting(Collections.<List<String>>emptyList()));
-            } else if ("maps".equals(name)) {
-                settings.put(key, new MapListSetting(Collections.<Map<String, String>>emptyList()));
+            if (entries != null) {
+                settings.put(key, new ListSetting(Collections.unmodifiableList(entries)));
+            } else if (lists != null) {
+                settings.put(key, new ListListSetting(Collections.unmodifiableList(lists)));
+            } else if (maps != null) {
+                settings.put(key, new MapListSetting(Collections.unmodifiableList(maps)));
             } else {
-                settings.put(key, new ListSetting(Collections.<String>emptyList()));
+                switch (name) {
+                    case "lists":
+                        settings.put(key, new ListListSetting(Collections.<List<String>>emptyList()));
+                        break;
+                    case "maps":
+                        settings.put(key, new MapListSetting(Collections.<Map<String, String>>emptyList()));
+                        break;
+                    default:
+                        settings.put(key, new ListSetting(Collections.<String>emptyList()));
+                        break;
+                }
             }
         }
     }
