Index: trunk/src/org/openstreetmap/josm/data/preferences/AbstractProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/AbstractProperty.java	(revision 12180)
+++ trunk/src/org/openstreetmap/josm/data/preferences/AbstractProperty.java	(revision 12181)
@@ -6,4 +6,5 @@
 import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
 import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
+import org.openstreetmap.josm.tools.ListenableWeakReference;
 
 /**
@@ -250,9 +251,26 @@
      */
     public void addWeakListener(ValueChangeListener<? super T> listener) {
-        addWeakListenerImpl(new PreferenceChangedListenerAdapter(listener));
-    }
-
-    protected void addWeakListenerImpl(PreferenceChangedListener adapter) {
-        getPreferences().addWeakKeyPreferenceChangeListener(getKey(), adapter);
+        ValueChangeListener<T> weakListener = new WeakPreferenceAdapter(listener);
+        PreferenceChangedListenerAdapter adapter = new PreferenceChangedListenerAdapter(weakListener);
+        addListenerImpl(adapter);
+    }
+
+    private class WeakPreferenceAdapter extends ListenableWeakReference<ValueChangeListener<? super T>>
+            implements ValueChangeListener<T> {
+        public WeakPreferenceAdapter(ValueChangeListener<? super T> referent) {
+            super(referent);
+        }
+
+        @Override
+        public void valueChanged(ValueChangeEvent<? extends T> e) {
+            ValueChangeListener<? super T> r = this.get();
+            r.valueChanged(e);
+        }
+
+        @Override
+        protected void onDereference() {
+            removeListenerImpl(new PreferenceChangedListenerAdapter(this));
+        }
+
     }
 
Index: trunk/src/org/openstreetmap/josm/data/preferences/AbstractToStringProperty.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/preferences/AbstractToStringProperty.java	(revision 12180)
+++ trunk/src/org/openstreetmap/josm/data/preferences/AbstractToStringProperty.java	(revision 12181)
@@ -57,16 +57,4 @@
             super.addListenerImpl(adapter);
             parent.addListenerImpl(adapter);
-        }
-
-        @Override
-        protected void addWeakListenerImpl(PreferenceChangedListener adapter) {
-            super.addWeakListenerImpl(adapter);
-            parent.addWeakListenerImpl(adapter);
-        }
-
-        @Override
-        protected void removeListenerImpl(PreferenceChangedListener adapter) {
-            super.removeListenerImpl(adapter);
-            parent.removeListenerImpl(adapter);
         }
 
Index: trunk/src/org/openstreetmap/josm/tools/ListenableWeakReference.java
===================================================================
--- trunk/src/org/openstreetmap/josm/tools/ListenableWeakReference.java	(revision 12181)
+++ trunk/src/org/openstreetmap/josm/tools/ListenableWeakReference.java	(revision 12181)
@@ -0,0 +1,69 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+import org.openstreetmap.josm.tools.bugreport.BugReport;
+
+/**
+ * This is a special weak reference that notifies a listener when it is no longer available.
+ *
+ * A special dereferenced-thread is used for this, so make sure your code is thread-safe.
+ * @author Michael Zangl
+ * @since 12181
+ *
+ * @param <T> The weak reference
+ */
+public class ListenableWeakReference<T> extends WeakReference<T> {
+    private static ReferenceQueue<Object> GLOBAL_QUEUE = new ReferenceQueue<>();
+    private static Thread thread;
+    private Runnable runOnDereference;
+
+    /**
+     * Create a new {@link ListenableWeakReference}
+     * @param referent The object that is referenced
+     */
+    public ListenableWeakReference(T referent) {
+        this(referent, () -> { });
+    }
+
+    /**
+     * Create a new {@link ListenableWeakReference}
+     * @param referent The object that is referenced
+     * @param runOnDereference The runnable to run when the object is no longer referenced.
+     */
+    public ListenableWeakReference(T referent, Runnable runOnDereference) {
+        super(referent, GLOBAL_QUEUE);
+        this.runOnDereference = runOnDereference;
+        ensureQueueStarted();
+    }
+
+    /**
+     * This method is called after the object is dereferenced.
+     */
+    protected void onDereference() {
+        this.runOnDereference.run();
+    }
+
+    private static synchronized void ensureQueueStarted() {
+        if (thread == null) {
+            thread = new Thread(ListenableWeakReference::clean, "Weak reference cleaner");
+            thread.start();
+        }
+    }
+
+    private static void clean() {
+        try {
+            while (true) {
+                Reference<? extends Object> ref = GLOBAL_QUEUE.remove();
+                if (ref instanceof ListenableWeakReference) {
+                    ((ListenableWeakReference<?>) ref).onDereference();
+                }
+            }
+        } catch (InterruptedException e) {
+            BugReport.intercept(e).warn();
+        }
+    }
+}
