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();
+        }
+    }
+}
Index: /trunk/test/unit/org/openstreetmap/josm/tools/ListenableWeakReferenceTest.java
===================================================================
--- /trunk/test/unit/org/openstreetmap/josm/tools/ListenableWeakReferenceTest.java	(revision 12181)
+++ /trunk/test/unit/org/openstreetmap/josm/tools/ListenableWeakReferenceTest.java	(revision 12181)
@@ -0,0 +1,55 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.tools;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.openstreetmap.josm.testutils.JOSMTestRules;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+/**
+ * Tests for {@link ListenableWeakReference}
+ * @author Michael Zangl
+ * @since 12181
+ */
+public class ListenableWeakReferenceTest {
+    /**
+     * Default test rules.
+     */
+    @Rule
+    @SuppressFBWarnings(value = "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
+    public JOSMTestRules test = new JOSMTestRules();
+    private Object object;
+    private boolean called;
+
+    /**
+     * Tests that {@link ListenableWeakReference#onDereference()} is called.
+     * @throws InterruptedException never
+     */
+    @Test
+    public void testOnDereference() throws InterruptedException {
+        object = new Object();
+        called = false;
+        ListenableWeakReference<Object> weak = new ListenableWeakReference<>(object, () -> called = true);
+        assertFalse(called);
+        assertSame(object, weak.get());
+
+        // now delete it
+        object = null;
+        System.gc();
+        System.runFinalization();
+        // now we wait for the listener thread
+        Thread.sleep(200);
+        assertTrue(called);
+
+        assertNotNull(weak);
+        assertNull(weak.get());
+    }
+
+}
