diff --git src/java/org/apache/fop/datatypes/LengthBase.java src/java/org/apache/fop/datatypes/LengthBase.java
index a0bfacb..00eaee8 100644
--- src/java/org/apache/fop/datatypes/LengthBase.java
+++ src/java/org/apache/fop/datatypes/LengthBase.java
@@ -142,33 +142,5 @@ public class LengthBase implements PercentBase {
     public Length getBaseLength() {
         return baseLength;
     }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((baseLength == null) ? 0 : baseLength.hashCode());
-        result = prime * result + baseType;
-        result = prime * result + ((fobj == null) ? 0 : fobj.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof LengthBase)) {
-            return false;
-        }
-        LengthBase other = (LengthBase) obj;
-        return eq(baseLength, other.baseLength)
-                && baseType == other.baseType
-                && eq(fobj, other.fobj);
-    }
-
-    private boolean eq(Object o1, Object o2) {
-        return o1 == null ? o2 == null : o1 == o2 || o1.equals(o2);
-    }
 }
 
diff --git src/java/org/apache/fop/datatypes/Numeric.java src/java/org/apache/fop/datatypes/Numeric.java
index e116244..2004c67 100644
--- src/java/org/apache/fop/datatypes/Numeric.java
+++ src/java/org/apache/fop/datatypes/Numeric.java
@@ -92,10 +92,4 @@ public interface Numeric {
      * @return the enum value
      */
     int getEnum();
-
-    @Override
-    int hashCode();
-
-    @Override
-    boolean equals(Object obj);
 }
diff --git src/java/org/apache/fop/datatypes/PercentBase.java src/java/org/apache/fop/datatypes/PercentBase.java
index dfe3cd9..6bc9ac9 100644
--- src/java/org/apache/fop/datatypes/PercentBase.java
+++ src/java/org/apache/fop/datatypes/PercentBase.java
@@ -50,9 +50,4 @@ public interface PercentBase {
      */
     int getBaseLength(PercentBaseContext context) throws PropertyException;
 
-    @Override
-    boolean equals(Object obj);
-
-    @Override
-    int hashCode();
 }
diff --git src/java/org/apache/fop/fo/expr/NCnameProperty.java src/java/org/apache/fop/fo/expr/NCnameProperty.java
index 6c0be3c..6bc16f2 100644
--- src/java/org/apache/fop/fo/expr/NCnameProperty.java
+++ src/java/org/apache/fop/fo/expr/NCnameProperty.java
@@ -79,23 +79,4 @@ public class NCnameProperty extends Property {
         return this.ncName;
     }
 
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((ncName == null) ? 0 : ncName.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof NCnameProperty)) {
-            return false;
-        }
-        NCnameProperty other = (NCnameProperty) obj;
-        return Property.eq(ncName, other.ncName);
-    }
 }
diff --git src/java/org/apache/fop/fo/expr/NumericProperty.java src/java/org/apache/fop/fo/expr/NumericProperty.java
index 5506c91..f80e1f5 100644
--- src/java/org/apache/fop/fo/expr/NumericProperty.java
+++ src/java/org/apache/fop/fo/expr/NumericProperty.java
@@ -23,8 +23,8 @@ import java.awt.Color;
 
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.datatypes.Length;
-import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.datatypes.PercentBaseContext;
+import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.fo.properties.FixedLength;
 import org.apache.fop.fo.properties.Property;
 
@@ -127,28 +127,4 @@ public class NumericProperty extends Property implements Numeric, Length {
             return value + "^" + dim;
         }
     }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + dim;
-        long temp;
-        temp = Double.doubleToLongBits(value);
-        result = prime * result + (int) (temp ^ (temp >>> 32));
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof NumericProperty)) {
-            return false;
-        }
-        NumericProperty other = (NumericProperty) obj;
-        return dim == other.dim
-                && Double.doubleToLongBits(value) == Double.doubleToLongBits(other.value);
-    }
 }
diff --git src/java/org/apache/fop/fo/expr/RelativeNumericProperty.java src/java/org/apache/fop/fo/expr/RelativeNumericProperty.java
index 0a7ce8e..8830700 100644
--- src/java/org/apache/fop/fo/expr/RelativeNumericProperty.java
+++ src/java/org/apache/fop/fo/expr/RelativeNumericProperty.java
@@ -20,8 +20,8 @@
 package org.apache.fop.fo.expr;
 
 import org.apache.fop.datatypes.Length;
-import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.datatypes.PercentBaseContext;
+import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.fo.properties.Property;
 import org.apache.fop.fo.properties.TableColLength;
 
@@ -173,7 +173,6 @@ public class RelativeNumericProperty extends Property implements Length {
      * Cast this numeric as a Length.
      * @return numeric value as length
      */
-    @Override
     public Length getLength() {
         if (dimension == 1) {
             return this;
@@ -183,7 +182,6 @@ public class RelativeNumericProperty extends Property implements Length {
     }
 
     /** @return numeric value */
-    @Override
     public Numeric getNumeric() {
         return this;
     }
@@ -274,7 +272,6 @@ public class RelativeNumericProperty extends Property implements Length {
      * Return a string represention of the expression. Only used for debugging.
      * @return the string representation.
      */
-    @Override
     public String toString() {
         switch (operation) {
         case ADDITION: case SUBTRACTION:
@@ -292,30 +289,4 @@ public class RelativeNumericProperty extends Property implements Length {
             return "unknown operation " + operation;
         }
     }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + dimension;
-        result = prime * result + ((op1 == null) ? 0 : op1.hashCode());
-        result = prime * result + ((op2 == null) ? 0 : op2.hashCode());
-        result = prime * result + operation;
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof RelativeNumericProperty)) {
-            return false;
-        }
-        RelativeNumericProperty other = (RelativeNumericProperty) obj;
-        return dimension == other.dimension
-                && Property.eq(op1, other.op1)
-                && Property.eq(op2, other.op2)
-                && operation == other.operation;
-    }
 }
diff --git src/java/org/apache/fop/fo/flow/Marker.java src/java/org/apache/fop/fo/flow/Marker.java
index 2b2d3b9..4588a9d 100644
--- src/java/org/apache/fop/fo/flow/Marker.java
+++ src/java/org/apache/fop/fo/flow/Marker.java
@@ -21,6 +21,9 @@ package org.apache.fop.fo.flow;
 
 import java.util.Map;
 
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.fo.FONode;
 import org.apache.fop.fo.FOTreeBuilderContext;
@@ -31,8 +34,6 @@ import org.apache.fop.fo.PropertyListMaker;
 import org.apache.fop.fo.ValidationException;
 import org.apache.fop.fo.properties.Property;
 import org.apache.fop.fo.properties.PropertyCache;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
 
 /**
  * Class modelling the <a href="http://www.w3.org/TR/xsl/#fo_marker">
@@ -356,8 +357,8 @@ public class Marker extends FObjMixed {
     /** Convenience inner class */
     public static final class MarkerAttribute {
 
-        private static final PropertyCache<MarkerAttribute> attributeCache
-                = new PropertyCache<MarkerAttribute>();
+        private static PropertyCache attributeCache
+                = new PropertyCache(MarkerAttribute.class);
 
         /** namespace */
         protected String namespace;
diff --git src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
index 72a7758..3c01181 100644
--- src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
+++ src/java/org/apache/fop/fo/properties/BackgroundPositionShorthand.java
@@ -72,37 +72,32 @@ public class BackgroundPositionShorthand extends ListProperty {
             return p;
         }
 
-        private static final class Dimension1PrecentBase implements PercentBase {
-            /** {@inheritDoc} */
-            public int getBaseLength(PercentBaseContext context) throws PropertyException {
-                return 0;
-            }
-
-            /** {@inheritDoc} */
-            public double getBaseValue() {
-                return 0;
-            }
-
-            /** {@inheritDoc} */
-            public int getDimension() {
-                return 1;
-            }
-        };
-
-        private static final Dimension1PrecentBase DIMENSION_1_PERCENT_BASE
-                = new Dimension1PrecentBase();
-
         /**
          * {@inheritDoc}
          * Returns a {@link org.apache.fop.datatypes.PercentBase} whose
          * <code>getDimension()</code> returns 1.
          */
         public PercentBase getPercentBase(PropertyList pl) {
-            return DIMENSION_1_PERCENT_BASE;
+            return new PercentBase() {
+                /** {@inheritDoc} */
+                public int getBaseLength(PercentBaseContext context) throws PropertyException {
+                    return 0;
+                }
+
+                /** {@inheritDoc} */
+                public double getBaseValue() {
+                    return 0;
+                }
+
+                /** {@inheritDoc} */
+                public int getDimension() {
+                    return 1;
+                }
+
+            };
         }
     }
 
-
     /**
      * Inner class to provide shorthand parsing capabilities
      *
diff --git src/java/org/apache/fop/fo/properties/CharacterProperty.java src/java/org/apache/fop/fo/properties/CharacterProperty.java
index 372b8e9..ebded4b 100644
--- src/java/org/apache/fop/fo/properties/CharacterProperty.java
+++ src/java/org/apache/fop/fo/properties/CharacterProperty.java
@@ -51,8 +51,8 @@ public final class CharacterProperty extends Property {
     }
 
     /** cache containing all canonical CharacterProperty instances */
-    private static final PropertyCache<CharacterProperty> CACHE
-        = new PropertyCache<CharacterProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(CharacterProperty.class);
 
     private final char character;
 
@@ -69,7 +69,8 @@ public final class CharacterProperty extends Property {
      * @return the character property instance
      */
     public static CharacterProperty getInstance(char character) {
-        return CACHE.fetch(new CharacterProperty(character));
+        return (CharacterProperty) CACHE.fetch(
+                        new CharacterProperty(character));
     }
 
     /**
diff --git src/java/org/apache/fop/fo/properties/ColorProperty.java src/java/org/apache/fop/fo/properties/ColorProperty.java
index 832e5ab..0550ce6 100644
--- src/java/org/apache/fop/fo/properties/ColorProperty.java
+++ src/java/org/apache/fop/fo/properties/ColorProperty.java
@@ -33,8 +33,8 @@ import org.apache.fop.util.ColorUtil;
 public final class ColorProperty extends Property  {
 
     /** cache holding canonical ColorProperty instances */
-    private static final PropertyCache<ColorProperty> CACHE
-        = new PropertyCache<ColorProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(ColorProperty.class);
 
     /**
      * The color represented by this property.
@@ -104,7 +104,7 @@ public final class ColorProperty extends Property  {
         ColorProperty instance = new ColorProperty(
                                        ColorUtil.parseColorString(
                                                foUserAgent, value));
-        return CACHE.fetch(instance);
+        return (ColorProperty)CACHE.fetch(instance);
     }
 
     /**
diff --git src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
index 58aa94c..d39dc24 100644
--- src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
+++ src/java/org/apache/fop/fo/properties/CommonBorderPaddingBackground.java
@@ -22,7 +22,11 @@ package org.apache.fop.fo.properties;
 import java.awt.Color;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.util.Arrays;
+
+import org.apache.xmlgraphics.image.loader.ImageException;
+import org.apache.xmlgraphics.image.loader.ImageInfo;
+import org.apache.xmlgraphics.image.loader.ImageManager;
+import org.apache.xmlgraphics.image.loader.ImageSessionContext;
 
 import org.apache.fop.ResourceEventProducer;
 import org.apache.fop.apps.FOUserAgent;
@@ -33,23 +37,19 @@ import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
-import org.apache.xmlgraphics.image.loader.ImageException;
-import org.apache.xmlgraphics.image.loader.ImageInfo;
-import org.apache.xmlgraphics.image.loader.ImageManager;
-import org.apache.xmlgraphics.image.loader.ImageSessionContext;
 
 /**
  * Stores all common border and padding properties.
  * See Sec. 7.7 of the XSL-FO Standard.
  */
-public final class CommonBorderPaddingBackground {
+public class CommonBorderPaddingBackground {                    // CSOK: FinalClassCheck
 
     /**
      *  cache holding all canonical instances
      *  (w/ absolute background-position-* and padding-*)
      */
-    private static final PropertyCache<CommonBorderPaddingBackground> CACHE
-        = new PropertyCache<CommonBorderPaddingBackground>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(CommonBorderPaddingBackground.class);
 
     private int hash = -1;
 
@@ -102,8 +102,8 @@ public final class CommonBorderPaddingBackground {
     public static final class BorderInfo {
 
         /** cache holding all canonical instances */
-        private static final PropertyCache<BorderInfo> CACHE
-            = new PropertyCache<BorderInfo>();
+        private static final PropertyCache CACHE
+            = new PropertyCache(BorderInfo.class);
 
         private int mStyle; // Enum for border style
         private Color mColor; // Border color
@@ -169,7 +169,6 @@ public final class CommonBorderPaddingBackground {
         }
 
         /** {@inheritDoc} */
-        @Override
         public String toString() {
             StringBuffer sb = new StringBuffer("BorderInfo");
             sb.append(" {");
@@ -183,22 +182,22 @@ public final class CommonBorderPaddingBackground {
         }
 
         /** {@inheritDoc} */
-        @Override
         public boolean equals(Object obj) {
             if (this == obj) {
                 return true;
             }
-            if (!(obj instanceof BorderInfo)) {
-                return false;
+
+            if (obj instanceof BorderInfo) {
+                BorderInfo bi = (BorderInfo)obj;
+                return (this.mColor == bi.mColor
+                    && this.mStyle == bi.mStyle
+                    && this.mWidth == bi.mWidth);
             }
-            BorderInfo other = (BorderInfo) obj;
-            return Property.eq(mColor, other.mColor)
-                    && mStyle == other.mStyle
-                    && Property.eq(mWidth, other.mWidth);
+
+            return false;
         }
 
         /** {@inheritDoc} */
-        @Override
         public int hashCode() {
             if (this.hash == -1) {
                 int hash = 17;
@@ -226,55 +225,46 @@ public final class CommonBorderPaddingBackground {
     private static class ConditionalNullLength extends CondLengthProperty {
 
         /** {@inheritDoc} */
-        @Override
         public Property getComponent(int cmpId) {
             throw new UnsupportedOperationException();
         }
 
         /** {@inheritDoc} */
-        @Override
         public Property getConditionality() {
             throw new UnsupportedOperationException();
         }
 
         /** {@inheritDoc} */
-        @Override
         public Length getLength() {
             throw new UnsupportedOperationException();
         }
 
         /** {@inheritDoc} */
-        @Override
         public Property getLengthComponent() {
             throw new UnsupportedOperationException();
         }
 
         /** {@inheritDoc} */
-        @Override
         public int getLengthValue() {
             return 0;
         }
 
         /** {@inheritDoc} */
-        @Override
         public int getLengthValue(PercentBaseContext context) {
             return 0;
         }
 
         /** {@inheritDoc} */
-        @Override
         public boolean isDiscard() {
             return true;
         }
 
         /** {@inheritDoc} */
-        @Override
         public void setComponent(int cmpId, Property cmpnValue, boolean isDefault) {
             throw new UnsupportedOperationException();
         }
 
         /** {@inheritDoc} */
-        @Override
         public String toString() {
             return "CondLength[0mpt, discard]";
         }
@@ -533,9 +523,9 @@ public final class CommonBorderPaddingBackground {
     }
 
     /**
-     * @param side the side of the border
-     * @param discard indicates whether the .conditionality component should be considered (end of a
-     * reference-area)
+     * @param side the side to retrieve
+     * @param discard indicates whether the .conditionality component should be
+     * considered (end of a reference-area)
      * @return the width of the start-border, taking into account the specified conditionality
      */
     public int getBorderWidth(int side, boolean discard) {
@@ -631,7 +621,6 @@ public final class CommonBorderPaddingBackground {
     }
 
     /** {@inheritDoc} */
-    @Override
     public String toString() {
         return "CommonBordersAndPadding (Before, After, Start, End):\n"
             + "Borders: (" + getBorderBeforeWidth(false) + ", " + getBorderAfterWidth(false) + ", "
@@ -743,55 +732,56 @@ public final class CommonBorderPaddingBackground {
     }
 
     /** {@inheritDoc} */
-    @Override
     public boolean equals(Object obj) {
         if (this == obj) {
             return true;
         }
-        if (!(obj instanceof CommonBorderPaddingBackground)) {
-            return false;
+        if (obj instanceof CommonBorderPaddingBackground) {
+            CommonBorderPaddingBackground cbpb = (CommonBorderPaddingBackground)obj;
+            return (this.backgroundAttachment == cbpb.backgroundAttachment
+                && this.backgroundColor == cbpb.backgroundColor
+                && this.backgroundImage.equals(cbpb.backgroundImage)
+                && this.backgroundPositionHorizontal == cbpb.backgroundPositionHorizontal
+                && this.backgroundPositionVertical == cbpb.backgroundPositionVertical
+                && this.backgroundRepeat == cbpb.backgroundRepeat
+                && this.borderInfo[BEFORE] == cbpb.borderInfo[BEFORE]
+                && this.borderInfo[AFTER] == cbpb.borderInfo[AFTER]
+                && this.borderInfo[START] == cbpb.borderInfo[START]
+                && this.borderInfo[END] == cbpb.borderInfo[END]
+                && this.padding[BEFORE] == cbpb.padding[BEFORE]
+                && this.padding[AFTER] == cbpb.padding[AFTER]
+                && this.padding[START] == cbpb.padding[START]
+                && this.padding[END] == cbpb.padding[END]);
         }
 
-        CommonBorderPaddingBackground other = (CommonBorderPaddingBackground) obj;
-        return backgroundAttachment == other.backgroundAttachment
-                && Property.eq(backgroundColor, other.backgroundColor)
-                && Property.eq(backgroundImage, other.backgroundImage)
-                && Property.eq(backgroundPositionHorizontal, backgroundPositionHorizontal)
-                && Property.eq(backgroundPositionVertical, other.backgroundPositionVertical)
-                && backgroundRepeat == other.backgroundRepeat
-                && Arrays.equals(borderInfo, other.borderInfo)
-                && Arrays.equals(padding, other.padding);
+        return false;
     }
 
     /** {@inheritDoc} */
-    @Override
     public int hashCode() {
         if (this.hash == -1) {
             int hash = 17;
-            hash += getHashCode(backgroundColor,
-                    backgroundImage,
-                    backgroundPositionHorizontal,
-                    backgroundPositionVertical,
-                    borderInfo[BEFORE],
-                    borderInfo[AFTER],
-                    borderInfo[START],
-                    borderInfo[END],
-                    padding[BEFORE],
-                    padding[AFTER],
-                    padding[START],
-                    padding[END]);
             hash = 37 * hash + backgroundAttachment;
+            hash = 37 * hash + (backgroundColor == null ? 0 : backgroundColor.hashCode());
+            hash = 37 * hash + (backgroundImage == null ? 0 : backgroundImage.hashCode());
+            hash = 37 * hash
+                + (backgroundPositionHorizontal == null
+                   ? 0 : backgroundPositionHorizontal.hashCode());
+            hash = 37 * hash
+                + (backgroundPositionVertical == null
+                   ? 0 : backgroundPositionVertical.hashCode());
             hash = 37 * hash + backgroundRepeat;
+            hash = 37 * hash + (borderInfo[BEFORE] == null ? 0 : borderInfo[BEFORE].hashCode());
+            hash = 37 * hash + (borderInfo[AFTER] == null ? 0 : borderInfo[AFTER].hashCode());
+            hash = 37 * hash + (borderInfo[START] == null ? 0 : borderInfo[START].hashCode());
+            hash = 37 * hash + (borderInfo[END] == null ? 0 : borderInfo[END].hashCode());
+            hash = 37 * hash + (padding[BEFORE] == null ? 0 : padding[BEFORE].hashCode());
+            hash = 37 * hash + (padding[AFTER] == null ? 0 : padding[AFTER].hashCode());
+            hash = 37 * hash + (padding[START] == null ? 0 : padding[START].hashCode());
+            hash = 37 * hash + (padding[END] == null ? 0 : padding[END].hashCode());
             this.hash = hash;
         }
-        return this.hash;
-    }
 
-    private int getHashCode(Object... objects) {
-        int hash = 0;
-        for (Object o : objects) {
-            hash = 37 * hash + (o == null ? 0 : o.hashCode());
-        }
-        return hash;
+        return this.hash;
     }
 }
diff --git src/java/org/apache/fop/fo/properties/CommonFont.java src/java/org/apache/fop/fo/properties/CommonFont.java
index f2f30ae..b12f84a 100644
--- src/java/org/apache/fop/fo/properties/CommonFont.java
+++ src/java/org/apache/fop/fo/properties/CommonFont.java
@@ -37,11 +37,11 @@ public final class CommonFont {
 
     /** cache holding canonical CommonFont instances (only those with
      *  absolute font-size and font-size-adjust) */
-    private static final PropertyCache<CommonFont> CACHE
-        = new PropertyCache<CommonFont>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(CommonFont.class);
 
     /** hashcode of this instance */
-    private int hash = -1;
+    private int hash = 0;
 
     /** The "font-family" property. */
     private final FontFamilyProperty fontFamily;
@@ -134,10 +134,10 @@ public final class CommonFont {
 
     /** @return an array with the font-family names */
     private String[] getFontFamily() {
-        List<Property> lst = fontFamily.getList();
+        List lst = fontFamily.getList();
         String[] fontFamily = new String[lst.size()];
         for (int i = 0, c = lst.size(); i < c; i++) {
-            fontFamily[i] = lst.get(i).getString();
+            fontFamily[i] = ((Property)lst.get(i)).getString();
         }
         return fontFamily;
     }
@@ -227,27 +227,34 @@ public final class CommonFont {
     }
 
     /** {@inheritDoc} */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj)
-            return true;
-        if (!(obj instanceof CommonFont)) {
+    public boolean equals(Object o) {
+
+        if (o == null) {
             return false;
         }
 
-        CommonFont other = (CommonFont) obj;
-        return Property.eq(fontFamily, other.fontFamily)
-                && Property.eq(fontSelectionStrategy, other.fontSelectionStrategy)
-                && Property.eq(fontSize, other.fontSize)
-                && Property.eq(fontSizeAdjust, other.fontSizeAdjust)
-                && Property.eq(fontStretch, other.fontStretch)
-                && Property.eq(fontStyle, other.fontStyle)
-                && Property.eq(fontVariant, other.fontVariant)
-                && Property.eq(fontWeight, other.fontWeight);
+        if (this == o) {
+            return true;
+        }
+
+        if (o instanceof CommonFont) {
+            CommonFont cf = (CommonFont) o;
+            return (cf.fontFamily == this.fontFamily)
+                    && (cf.fontSelectionStrategy == this.fontSelectionStrategy)
+                    && (cf.fontStretch == this.fontStretch)
+                    && (cf.fontStyle == this.fontStyle)
+                    && (cf.fontVariant == this.fontVariant)
+                    && (cf.fontWeight == this.fontWeight)
+                    && (cf.fontSize == this.fontSize)
+                    && (cf.fontSizeAdjust == this.fontSizeAdjust);
+        }
+        return false;
+
     }
 
     /** {@inheritDoc} */
     public int hashCode() {
+
         if (this.hash == -1) {
             int hash = 17;
             hash = 37 * hash + (fontSize == null ? 0 : fontSize.hashCode());
@@ -258,9 +265,10 @@ public final class CommonFont {
             hash = 37 * hash + (fontStretch == null ? 0 : fontStretch.hashCode());
             hash = 37 * hash + (fontStyle == null ? 0 : fontStyle.hashCode());
             hash = 37 * hash + (fontVariant == null ? 0 : fontVariant.hashCode());
-            hash = 37 * hash + (fontWeight == null ? 0 : fontWeight.hashCode());
+            hash = 37 * hash + (fontStretch == null ? 0 : fontStretch.hashCode());
             this.hash = hash;
         }
         return hash;
+
     }
 }
diff --git src/java/org/apache/fop/fo/properties/CommonHyphenation.java src/java/org/apache/fop/fo/properties/CommonHyphenation.java
index 621e2a7..7b9b5bc 100644
--- src/java/org/apache/fop/fo/properties/CommonHyphenation.java
+++ src/java/org/apache/fop/fo/properties/CommonHyphenation.java
@@ -21,6 +21,7 @@ package org.apache.fop.fo.properties;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.apache.fop.fo.Constants;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
@@ -37,8 +38,7 @@ public final class CommonHyphenation {
     /** Logger */
     private static final Log LOG = LogFactory.getLog(CommonHyphenation.class);
 
-    private static final PropertyCache<CommonHyphenation> CACHE =
-            new PropertyCache<CommonHyphenation>();
+    private static final PropertyCache CACHE = new PropertyCache(CommonHyphenation.class);
 
     private int hash = 0;
 
@@ -118,6 +118,7 @@ public final class CommonHyphenation {
                                 hyphenationRemainCharacterCount);
 
         return CACHE.fetch(instance);
+
     }
 
     private static final char HYPHEN_MINUS = '-';
diff --git src/java/org/apache/fop/fo/properties/CondLengthProperty.java src/java/org/apache/fop/fo/properties/CondLengthProperty.java
index 42ce89e..1ab7ec3 100644
--- src/java/org/apache/fop/fo/properties/CondLengthProperty.java
+++ src/java/org/apache/fop/fo/properties/CondLengthProperty.java
@@ -33,8 +33,8 @@ import org.apache.fop.fo.expr.PropertyException;
 public class CondLengthProperty extends Property implements CompoundDatatype {
 
     /** cache holding canonical instances (for absolute conditional lengths) */
-    private static final PropertyCache<CondLengthProperty> CACHE
-        = new PropertyCache<CondLengthProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(CondLengthProperty.class);
 
     /** components */
     private Property length;
@@ -159,7 +159,7 @@ public class CondLengthProperty extends Property implements CompoundDatatype {
      */
     public CondLengthProperty getCondLength() {
         if (this.length.getLength().isAbsolute()) {
-            CondLengthProperty clp = CACHE.fetch(this);
+            CondLengthProperty clp = (CondLengthProperty) CACHE.fetch(this);
             if (clp == this) {
                 isCached = true;
             }
diff --git src/java/org/apache/fop/fo/properties/EnumLength.java src/java/org/apache/fop/fo/properties/EnumLength.java
index aacf170..d2480be 100644
--- src/java/org/apache/fop/fo/properties/EnumLength.java
+++ src/java/org/apache/fop/fo/properties/EnumLength.java
@@ -93,20 +93,5 @@ public class EnumLength extends LengthProperty {
         return enumProperty.getObject();
     }
 
-    @Override
-    public int hashCode() {
-        return enumProperty.hashCode();
-    }
 
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof EnumLength)) {
-            return false;
-        }
-        EnumLength other = (EnumLength) obj;
-        return Property.eq(enumProperty, other.enumProperty);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/EnumNumber.java src/java/org/apache/fop/fo/properties/EnumNumber.java
index 12e0d96..153a716 100644
--- src/java/org/apache/fop/fo/properties/EnumNumber.java
+++ src/java/org/apache/fop/fo/properties/EnumNumber.java
@@ -29,8 +29,8 @@ import org.apache.fop.fo.expr.PropertyException;
 public final class EnumNumber extends Property implements Numeric {
 
     /** cache holding all canonical EnumNumber instances */
-    private static final PropertyCache<EnumNumber> CACHE
-        = new PropertyCache<EnumNumber>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(EnumNumber.class);
 
     private final EnumProperty enumProperty;
 
@@ -50,7 +50,8 @@ public final class EnumNumber extends Property implements Numeric {
      * @return  the canonical instance
      */
     public static EnumNumber getInstance(Property enumProperty) {
-        return CACHE.fetch(new EnumNumber((EnumProperty) enumProperty));
+        return (EnumNumber)CACHE.fetch(
+                new EnumNumber((EnumProperty) enumProperty));
     }
 
     /** {@inheritDoc} */
@@ -68,20 +69,16 @@ public final class EnumNumber extends Property implements Numeric {
         return enumProperty.getObject();
     }
 
-    @Override
+    /** {@inheritDoc} */
     public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof EnumNumber)) {
+        if (obj instanceof EnumNumber) {
+            return (((EnumNumber)obj).enumProperty == this.enumProperty);
+        } else {
             return false;
         }
-        EnumNumber other = (EnumNumber) obj;
-        return Property.eq(enumProperty, other.enumProperty);
     }
 
     /** {@inheritDoc} */
-    @Override
     public int hashCode() {
         return enumProperty.hashCode();
     }
diff --git src/java/org/apache/fop/fo/properties/EnumProperty.java src/java/org/apache/fop/fo/properties/EnumProperty.java
index 6de65ca..ae704f1 100644
--- src/java/org/apache/fop/fo/properties/EnumProperty.java
+++ src/java/org/apache/fop/fo/properties/EnumProperty.java
@@ -29,8 +29,8 @@ import org.apache.fop.fo.expr.PropertyException;
 public final class EnumProperty extends Property {
 
     /** cache holding all canonical EnumProperty instances */
-    private static final PropertyCache<EnumProperty> CACHE
-        = new PropertyCache<EnumProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(EnumProperty.class);
 
     /**
      * Inner class for creating EnumProperty instances
@@ -93,7 +93,8 @@ public final class EnumProperty extends Property {
      * @return an enumeration property
      */
     public static EnumProperty getInstance(int explicitValue, String text) {
-        return CACHE.fetch(new EnumProperty(explicitValue, text));
+        return (EnumProperty) CACHE.fetch(
+                        new EnumProperty(explicitValue, text));
     }
 
     /**
@@ -116,8 +117,10 @@ public final class EnumProperty extends Property {
     public boolean equals(Object obj) {
         if (obj instanceof EnumProperty) {
             EnumProperty ep = (EnumProperty)obj;
-            return this.value == ep.value
-                    && Property.eq(text, ep.text);
+            return (ep.value == this.value)
+                && ((ep.text == this.text)
+                    || (ep.text != null
+                        && ep.text.equals(this.text)));
         } else {
             return false;
         }
diff --git src/java/org/apache/fop/fo/properties/FixedLength.java src/java/org/apache/fop/fo/properties/FixedLength.java
index 8f1c3f3..c35c6f6 100644
--- src/java/org/apache/fop/fo/properties/FixedLength.java
+++ src/java/org/apache/fop/fo/properties/FixedLength.java
@@ -45,8 +45,8 @@ public final class FixedLength extends LengthProperty {
     public static final String MPT = "mpt";
 
     /** cache holding all canonical FixedLength instances */
-    private static final PropertyCache<FixedLength> CACHE
-        = new PropertyCache<FixedLength>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(FixedLength.class);
 
     /** canonical zero-length instance */
     public static final FixedLength ZERO_FIXED_LENGTH = new FixedLength(0, FixedLength.MPT, 1.0f);
@@ -82,8 +82,10 @@ public final class FixedLength extends LengthProperty {
         if (numUnits == 0.0) {
             return ZERO_FIXED_LENGTH;
         } else {
-            return CACHE.fetch(new FixedLength(numUnits, units, sourceResolution));
+            return (FixedLength)CACHE.fetch(
+                new FixedLength(numUnits, units, sourceResolution));
         }
+
     }
 
     /**
diff --git src/java/org/apache/fop/fo/properties/FontFamilyProperty.java src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
index e5b19fa..f6fa806 100644
--- src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
+++ src/java/org/apache/fop/fo/properties/FontFamilyProperty.java
@@ -31,8 +31,8 @@ import org.apache.fop.fo.expr.PropertyException;
 public final class FontFamilyProperty extends ListProperty {
 
     /** cache holding all canonical FontFamilyProperty instances */
-    private static final PropertyCache<FontFamilyProperty> CACHE
-        = new PropertyCache<FontFamilyProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(FontFamilyProperty.class);
 
     private int hash = 0;
 
diff --git src/java/org/apache/fop/fo/properties/KeepProperty.java src/java/org/apache/fop/fo/properties/KeepProperty.java
index 64b8f22..9d04ce7 100644
--- src/java/org/apache/fop/fo/properties/KeepProperty.java
+++ src/java/org/apache/fop/fo/properties/KeepProperty.java
@@ -30,8 +30,8 @@ import org.apache.fop.fo.expr.PropertyException;
 public final class KeepProperty extends Property implements CompoundDatatype {
 
     /** class holding all canonical KeepProperty instances*/
-    private static final PropertyCache<KeepProperty> CACHE
-        = new PropertyCache<KeepProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(KeepProperty.class);
 
     private boolean isCachedValue = false;
     private Property withinLine;
@@ -165,7 +165,7 @@ public final class KeepProperty extends Property implements CompoundDatatype {
      *          this property
      */
     public KeepProperty getKeep() {
-        KeepProperty keep = CACHE.fetch(this);
+        KeepProperty keep = (KeepProperty) CACHE.fetch(this);
         /* make sure setComponent() can never alter cached values */
         keep.isCachedValue = true;
         return keep;
diff --git src/java/org/apache/fop/fo/properties/LengthPairProperty.java src/java/org/apache/fop/fo/properties/LengthPairProperty.java
index b40b078..9840c46 100644
--- src/java/org/apache/fop/fo/properties/LengthPairProperty.java
+++ src/java/org/apache/fop/fo/properties/LengthPairProperty.java
@@ -150,24 +150,4 @@ public class LengthPairProperty extends Property implements CompoundDatatype {
         return this;
     }
 
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((bpd == null) ? 0 : bpd.hashCode());
-        result = prime * result + ((ipd == null) ? 0 : ipd.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof LengthPairProperty)) {
-            return false;
-        }
-        LengthPairProperty other = (LengthPairProperty) obj;
-        return Property.eq(bpd, other.bpd) && Property.eq(ipd, other.ipd);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/LengthProperty.java src/java/org/apache/fop/fo/properties/LengthProperty.java
index 28404e3..3f56905 100644
--- src/java/org/apache/fop/fo/properties/LengthProperty.java
+++ src/java/org/apache/fop/fo/properties/LengthProperty.java
@@ -19,12 +19,13 @@
 
 package org.apache.fop.fo.properties;
 
+import org.apache.xmlgraphics.util.UnitConv;
+
 import org.apache.fop.datatypes.Length;
 import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
-import org.apache.xmlgraphics.util.UnitConv;
 
 /**
  * Superclass for properties wrapping a Length value.
@@ -47,7 +48,6 @@ public abstract class LengthProperty extends Property
         }
 
         /** {@inheritDoc} */
-        @Override
         public Property convertProperty(Property p,
                                         PropertyList propertyList,
                                         FObj fo) throws PropertyException {
@@ -80,27 +80,19 @@ public abstract class LengthProperty extends Property
     }
 
     /** @return this.length cast as a Numeric */
-    @Override
     public Numeric getNumeric() {
         return this;
     }
 
     /** @return this.length */
-    @Override
     public Length getLength() {
         return this;
     }
 
     /** @return this.length cast as an Object */
-    @Override
     public Object getObject() {
         return this;
     }
 
-    @Override
-    public abstract int hashCode();
-
-    @Override
-    public abstract boolean equals(Object obj);
 }
 
diff --git src/java/org/apache/fop/fo/properties/LengthRangeProperty.java src/java/org/apache/fop/fo/properties/LengthRangeProperty.java
index b8d7138..d8e8ee2 100644
--- src/java/org/apache/fop/fo/properties/LengthRangeProperty.java
+++ src/java/org/apache/fop/fo/properties/LengthRangeProperty.java
@@ -314,31 +314,4 @@ public class LengthRangeProperty extends Property implements CompoundDatatype {
         return this;
     }
 
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + bfSet;
-        result = prime * result + (consistent ? 1231 : 1237);
-        result = prime * result + ((maximum == null) ? 0 : maximum.hashCode());
-        result = prime * result + ((minimum == null) ? 0 : minimum.hashCode());
-        result = prime * result + ((optimum == null) ? 0 : optimum.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof LengthRangeProperty)) {
-            return false;
-        }
-        LengthRangeProperty other = (LengthRangeProperty) obj;
-        return bfSet == other.bfSet
-                && consistent == other.consistent
-                && Property.eq(maximum, other.maximum)
-                && Property.eq(minimum, other.minimum)
-                && Property.eq(optimum, other.optimum);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/ListProperty.java src/java/org/apache/fop/fo/properties/ListProperty.java
index 8c6d49b..6b1ffce 100644
--- src/java/org/apache/fop/fo/properties/ListProperty.java
+++ src/java/org/apache/fop/fo/properties/ListProperty.java
@@ -105,20 +105,4 @@ public class ListProperty extends Property {
         return list;
     }
 
-    @Override
-    public int hashCode() {
-        return list.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof ListProperty)) {
-            return false;
-        }
-        ListProperty other = (ListProperty) obj;
-        return Property.eq(list, other.list);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/NumberProperty.java src/java/org/apache/fop/fo/properties/NumberProperty.java
index 01e14cc..97844d7 100644
--- src/java/org/apache/fop/fo/properties/NumberProperty.java
+++ src/java/org/apache/fop/fo/properties/NumberProperty.java
@@ -106,8 +106,8 @@ public final class NumberProperty extends Property implements Numeric {
     }
 
     /** cache holding all canonical NumberProperty instances */
-    private static final PropertyCache<NumberProperty> CACHE
-        = new PropertyCache<NumberProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(NumberProperty.class);
 
     private final Number number;
 
@@ -144,7 +144,8 @@ public final class NumberProperty extends Property implements Numeric {
      * @return  the canonical NumberProperty
      */
     public static NumberProperty getInstance(Double num) {
-        return CACHE.fetch(new NumberProperty(num.doubleValue()));
+        return (NumberProperty)CACHE.fetch(
+                    new NumberProperty(num.doubleValue()));
     }
 
     /**
@@ -154,7 +155,8 @@ public final class NumberProperty extends Property implements Numeric {
      * @return  the canonical NumberProperty
      */
     public static NumberProperty getInstance(Integer num) {
-        return CACHE.fetch(new NumberProperty(num.intValue()));
+        return (NumberProperty)CACHE.fetch(
+                    new NumberProperty(num.intValue()));
     }
 
     /**
@@ -164,7 +166,8 @@ public final class NumberProperty extends Property implements Numeric {
      * @return  the canonical NumberProperty
      */
     public static NumberProperty getInstance(double num) {
-        return CACHE.fetch(new NumberProperty(num));
+        return (NumberProperty)CACHE.fetch(
+                    new NumberProperty(num));
     }
 
     /**
@@ -174,7 +177,8 @@ public final class NumberProperty extends Property implements Numeric {
      * @return  the canonical NumberProperty
      */
     public static NumberProperty getInstance(int num) {
-        return CACHE.fetch(new NumberProperty(num));
+        return (NumberProperty)CACHE.fetch(
+                    new NumberProperty(num));
     }
 
     /**
@@ -265,21 +269,21 @@ public final class NumberProperty extends Property implements Numeric {
     }
 
     /** {@inheritDoc} */
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof NumberProperty)) {
-            return false;
-        }
-        NumberProperty other = (NumberProperty) obj;
-        return Property.eq(number, other.number);
+    public int hashCode() {
+        return number.hashCode();
     }
 
     /** {@inheritDoc} */
-    @Override
-    public int hashCode() {
-        return number.hashCode();
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof NumberProperty) {
+            NumberProperty np = (NumberProperty) o;
+            return (np.number == this.number
+                    || (this.number != null
+                        && this.number.equals(np.number)));
+        }
+        return false;
     }
 }
diff --git src/java/org/apache/fop/fo/properties/PercentLength.java src/java/org/apache/fop/fo/properties/PercentLength.java
index 4e7f6b8..66f1f17 100644
--- src/java/org/apache/fop/fo/properties/PercentLength.java
+++ src/java/org/apache/fop/fo/properties/PercentLength.java
@@ -19,8 +19,8 @@
 
 package org.apache.fop.fo.properties;
 
-import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.datatypes.PercentBaseContext;
+import org.apache.fop.datatypes.PercentBase;
 import org.apache.fop.fo.expr.PropertyException;
 
 /**
@@ -40,6 +40,8 @@ public class PercentLength extends LengthProperty {
      */
     private PercentBase lbase = null;
 
+    private double resolvedValue;
+
     /**
      * Main constructor. Construct an object based on a factor (the percent,
      * as a factor) and an object which has a method to return the Length which
@@ -86,7 +88,8 @@ public class PercentLength extends LengthProperty {
     /** {@inheritDoc} */
     public double getNumericValue(PercentBaseContext context) {
         try {
-            return factor * lbase.getBaseLength(context);
+            resolvedValue = factor * lbase.getBaseLength(context);
+            return resolvedValue;
         } catch (PropertyException exc) {
             log.error(exc);
             return 0;
@@ -121,27 +124,4 @@ public class PercentLength extends LengthProperty {
         return sb.toString();
     }
 
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        long temp;
-        temp = Double.doubleToLongBits(factor);
-        result = prime * result + (int) (temp ^ (temp >>> 32));
-        result = prime * result + ((lbase == null) ? 0 : lbase.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof PercentLength)) {
-            return false;
-        }
-        PercentLength other = (PercentLength) obj;
-        return Double.doubleToLongBits(factor) == Double.doubleToLongBits(other.factor)
-                && Property.eq(lbase, other.lbase);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/Property.java src/java/org/apache/fop/fo/properties/Property.java
index 7f744eb..a04f96a 100644
--- src/java/org/apache/fop/fo/properties/Property.java
+++ src/java/org/apache/fop/fo/properties/Property.java
@@ -19,11 +19,12 @@
 
 package org.apache.fop.fo.properties;
 
-import java.awt.Color;
 import java.util.List;
+import java.awt.Color;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.apache.fop.apps.FOUserAgent;
 import org.apache.fop.datatypes.Length;
 import org.apache.fop.datatypes.Numeric;
@@ -32,7 +33,7 @@ import org.apache.fop.fo.Constants;
 /**
  * Base class for all property objects
  */
-public abstract class Property {
+public class Property {
 
     /** Logger for all property classes */
     protected static final Log log = LogFactory.getLog(PropertyMaker.class);
@@ -198,23 +199,4 @@ public abstract class Property {
         }
         return "";
     }
-
-    /*
-     * Ensure hashCode() and equals() are implemented so that PropertyCache works well.
-     */
-    @Override
-    public abstract int hashCode();
-
-    @Override
-    public abstract boolean equals(Object obj);
-
-    /**
-     * Compares two objects for object equality.
-     * @param o1 object used in comparison
-     * @param o2 object used in comparison
-     * @return true if either o1 and o2 are null or if o1.equals(o2)
-     */
-    protected static boolean eq(Object o1, Object o2) {
-        return o1 == null ? o2 == null : o1 == o2 || o1.equals(o2);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/PropertyCache.java src/java/org/apache/fop/fo/properties/PropertyCache.java
index 94a134c..9201257 100644
--- src/java/org/apache/fop/fo/properties/PropertyCache.java
+++ src/java/org/apache/fop/fo/properties/PropertyCache.java
@@ -19,85 +19,297 @@
 
 package org.apache.fop.fo.properties;
 
-import java.lang.ref.WeakReference;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import org.apache.fop.fo.flow.Marker;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
 
 /**
- * Thread-safe cache that minimizes the memory requirements by fetching an instance from the cache
- * that is equal to the given one. Internally the instances are stored in WeakReferences in order to
- * be reclaimed when they are no longer referenced.
- * @param <T> The type of values that are cached
+ *  Dedicated cache, meant for storing canonical instances
+ *  of property-related classes.
+ *  The public access points are overloaded <code>fetch()</code> methods
+ *  that each correspond to a cached type.
+ *  It is designed especially to be used concurrently by multiple threads,
+ *  drawing heavily upon the principles behind Java 1.5's
+ *  <code>ConcurrentHashMap</code>.
  */
-public final class PropertyCache<T> {
+public final class PropertyCache {
 
-    private static final Log log = LogFactory.getLog(PropertyCache.class);
+    private static final int SEGMENT_COUNT = 32; //0x20
+    private static final int INITIAL_BUCKET_COUNT = SEGMENT_COUNT;
 
+    /** bitmask to apply to the hash to get to the
+     *  corresponding cache segment */
+    private static final int SEGMENT_MASK = SEGMENT_COUNT - 1; //0x1F
     /**
-     * Determines if the cache is used based on the value of the system property
-     * org.apache.fop.fo.properties.use-cache
+     * Indicates whether the cache should be used at all
+     * Can be controlled by the system property:
+     *   org.apache.fop.fo.properties.use-cache
      */
     private final boolean useCache;
 
-    /**
-     * The underlying map that stores WeakReferences to the cached entries. The map keys are the
-     * hashCode of the cached entries. The map values are a WeakRefence to the cached entries. When
-     * two cached entries have the same hashcode, the last one is kept but this should be an
-     * exception case (otherwise the hashCode() method of T needs to be fixed).
-     */
-    private final ConcurrentMap<Integer, WeakReference<T>> map;
+    /** the segments array (length = 32) */
+    private CacheSegment[] segments = new CacheSegment[SEGMENT_COUNT];
+    /** the table of hash-buckets */
+    private CacheEntry[] table = new CacheEntry[INITIAL_BUCKET_COUNT];
 
-    /**
-     * Counts the number of entries put in the map in order to periodically check and remove the
-     * entries whose referents have been reclaimed.
+    private Class runtimeType;
+
+    private final boolean[] votesForRehash = new boolean[SEGMENT_COUNT];
+
+    /* same hash function as used by java.util.HashMap */
+    private static int hash(Object x) {
+        return hash(x.hashCode());
+    }
+
+    private static int hash(int hashCode) {
+        int h = hashCode;
+        h += ~(h << 9);
+        h ^= (h >>> 14);
+        h += (h << 4);
+        h ^= (h >>> 10);
+        return h;
+    }
+
+    /* shortcut function */
+    private static boolean eq(Object p, Object q) {
+        return (p == q || (p != null && p.equals(q)));
+    }
+
+    /* Class modeling a cached entry */
+    private static class CacheEntry extends WeakReference {
+        private volatile CacheEntry nextEntry;
+        private final int hash;
+
+        /* main constructor */
+        public CacheEntry(Object p, CacheEntry nextEntry, ReferenceQueue refQueue) {
+            super(p, refQueue);
+            this.nextEntry = nextEntry;
+            this.hash = hash(p);
+        }
+
+        /* main constructor */
+        public CacheEntry(Object p, CacheEntry nextEntry) {
+            super(p);
+            this.nextEntry = nextEntry;
+            this.hash = hash(p);
+        }
+
+    }
+
+    /* Wrapper objects to synchronize on */
+    private static final class CacheSegment {
+        CacheSegment() {
+        }
+        private int count = 0;
+        int getCount() {
+            return count;
+        }
+    }
+
+    private void cleanSegment(int segmentIndex) {
+        CacheSegment segment = segments[segmentIndex];
+
+        int oldCount = segment.count;
+
+        /* clean all buckets in this segment */
+        for (int bucketIndex = segmentIndex;
+                    bucketIndex < table.length;
+                    bucketIndex += SEGMENT_COUNT) {
+            CacheEntry prev = null;
+            CacheEntry entry = table[bucketIndex];
+            if (entry == null) {
+                continue;
+            }
+            do {
+                if (entry.get() == null) {
+                    if (prev == null) {
+                        table[bucketIndex] = entry.nextEntry;
+                    } else {
+                        prev.nextEntry = entry.nextEntry;
+                    }
+                    segment.count--;
+                    assert segment.count >= 0;
+                } else {
+                    prev = entry;
+                }
+                entry = entry.nextEntry;
+            } while (entry != null);
+        }
+
+        synchronized (votesForRehash) {
+            if (oldCount > segment.count) {
+                votesForRehash[segmentIndex] = false;
+                return;
+            }
+            /* cleanup had no effect */
+            if (!votesForRehash[segmentIndex]) {
+                /* first time for this segment */
+                votesForRehash[segmentIndex] = true;
+                int voteCount = 0;
+                for (int i = SEGMENT_MASK + 1; --i >= 0;) {
+                    if (votesForRehash[i]) {
+                        voteCount++;
+                    }
+                }
+                if (voteCount > SEGMENT_MASK / 4) {
+                    rehash(SEGMENT_MASK);
+                    /* reset votes */
+                    for (int i = SEGMENT_MASK + 1; --i >= 0;) {
+                        votesForRehash[i] = false;
+                    }
+
+                }
+            }
+        }
+    }
+
+    /*
+     * Puts a new instance in the cache.
+     * If the total number of entries for the corresponding
+     * segment exceeds twice the amount of hash-buckets, a
+     * cleanup will be performed to try and remove obsolete
+     * entries.
      */
-    private final AtomicInteger putCounter;
-    
-    /**
-     * Lock to prevent concurrent cleanup of the map.
+    private void put(Object o) {
+
+        int hash = hash(o);
+        int segmentIndex = hash & SEGMENT_MASK;
+        CacheSegment segment = segments[segmentIndex];
+
+        synchronized (segment) {
+            int index = hash & (table.length - 1);
+            CacheEntry entry = table[index];
+
+            if (entry == null) {
+                entry = new CacheEntry(o, null);
+                table[index] = entry;
+                segment.count++;
+            } else {
+                Object p = entry.get();
+                if (eq(p, o)) {
+                    return;
+                } else {
+                    CacheEntry newEntry = new CacheEntry(o, entry);
+                    table[index] = newEntry;
+                    segment.count++;
+                }
+            }
+
+            if (segment.count > (2 * table.length)) {
+                  cleanSegment(segmentIndex);
+            }
+        }
+    }
+
+
+    /* Gets a cached instance. Returns null if not found */
+    private Object get(Object o) {
+
+        int hash = hash(o);
+        int index = hash & (table.length - 1);
+
+        CacheEntry entry = table[index];
+        Object q;
+
+        /* try non-synched first */
+        for (CacheEntry e = entry; e != null; e = e.nextEntry) {
+            if ( e.hash == hash ) {
+                q = e.get();
+                if ( ( q != null ) &&  eq ( q, o ) ) {
+                    return q;
+                }
+            }
+        }
+
+        /* retry synched, only if the above attempt did not succeed,
+         * as another thread may, in the meantime, have added a
+         * corresponding entry */
+        CacheSegment segment = segments[hash & SEGMENT_MASK];
+        synchronized (segment) {
+            entry = table[index];
+            for (CacheEntry e = entry; e != null; e = e.nextEntry) {
+                if ( e.hash == hash ) {
+                    q = e.get();
+                    if ( ( q != null ) &&  eq ( q, o ) ) {
+                        return q;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    /*
+     * Recursively acquires locks on all 32 segments,
+     * extends the cache and redistributes the entries.
+     *
      */
-    private final Lock cleanupLock;
+    private void rehash(int index) {
+
+        CacheSegment seg = segments[index];
+        synchronized (seg) {
+            if (index > 0) {
+                /* need to recursively acquire locks on all segments */
+                rehash(index - 1);
+            } else {
+                /* double the amount of buckets */
+                int newLength = table.length << 1;
+                if (newLength > 0) { //no overflow?
+                    /* reset segment counts */
+                    for (int i = segments.length; --i >= 0;) {
+                        segments[i].count = 0;
+                    }
+
+                    CacheEntry[] newTable = new CacheEntry[newLength];
 
-    private final AtomicInteger hashCodeCollisionCounter;
+                    int hash, idx;
+                    Object o;
+                    newLength--;
+                    for (int i = table.length; --i >= 0;) {
+                        for (CacheEntry c = table[i]; c != null; c = c.nextEntry) {
+                            o = c.get();
+                            if (o != null) {
+                                hash = c.hash;
+                                idx = hash & newLength;
+                                newTable[idx] = new CacheEntry(o, newTable[idx]);
+                                segments[hash & SEGMENT_MASK].count++;
+                            }
+                        }
+                    }
+                    table = newTable;
+                }
+            }
+        }
+    }
 
     /**
-     * Unless the "use-cache" property is set to "false", the property cache is instantiated. If
-     * "use-cache" is set to false, an empty class is made, an no caching is performed.
+     *  Default constructor.
+     *
+     *  @param c    Runtime type of the objects that will be stored in the cache
      */
-    public PropertyCache() {
-        this.useCache = Boolean.valueOf(
-                System.getProperty("org.apache.fop.fo.properties.use-cache", "true"))
-                .booleanValue();
+    public PropertyCache(Class c) {
+        this.useCache = Boolean.valueOf(System.getProperty(
+                            "org.apache.fop.fo.properties.use-cache", "true")
+                        ).booleanValue();
         if (useCache) {
-            map = new ConcurrentHashMap<Integer, WeakReference<T>>();
-            putCounter = new AtomicInteger();
-            cleanupLock = new ReentrantLock();
-            hashCodeCollisionCounter = new AtomicInteger();
-        } else {
-            map = null;
-            putCounter = null;
-            cleanupLock = null;
-            hashCodeCollisionCounter = null;
+            for (int i = SEGMENT_MASK + 1; --i >= 0;) {
+                segments[i] = new CacheSegment();
+            }
         }
+        this.runtimeType = c;
     }
 
     /**
-     * Checks if the given Object is present in the cache - if so, returns a reference to the cached
-     * instance. Otherwise the given object is added to the cache and returned.
+     *  Generic fetch() method.
+     *  Checks if the given <code>Object</code> is present in the cache -
+     *  if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
      *
-     * @param obj
-     *            the Object to check for
-     * @return the cached instance
+     *  @param obj   the Object to check for
+     *  @return  the cached instance
      */
-    public T fetch(T obj) {
+    private Object fetch(Object obj) {
         if (!this.useCache) {
             return obj;
         }
@@ -106,80 +318,96 @@ public final class PropertyCache<T> {
             return null;
         }
 
-        Integer hashCode = Integer.valueOf(obj.hashCode());
+        Object cacheEntry = get(obj);
+        if (cacheEntry != null) {
+            return cacheEntry;
+        }
+        put(obj);
+        return obj;
+    }
 
-        WeakReference<T> weakRef = map.get(hashCode);
-        if (weakRef == null) {
-            weakRef = map.putIfAbsent(hashCode, new WeakReference<T>(obj));
-            attemptCleanup();
+    /**
+     *  Checks if the given {@link Property} is present in the cache -
+     *  if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param prop the Property instance to check for
+     *  @return the cached instance
+     */
+    public Property fetch(Property prop) {
 
-            if (weakRef == null) {
-                return obj;
-            }
-            // else another thread added a value, continue.
-        }
+        return (Property) fetch((Object) prop);
+    }
 
-        T cached = weakRef.get();
-        if (cached != null) {
-            if (eq(cached, obj)) {
-                return cached;
-            } else {
-                /*
-                 * Log a message when obj.getClass() does not implement correctly the equals() or
-                 * hashCode() method. It is expected that only very few objects will have the
-                 * same hashCode but will not be equal.
-                 */
-                if ((hashCodeCollisionCounter.incrementAndGet() % 10) == 0) {
-                    log.info(hashCodeCollisionCounter.get() + " hashCode() collisions for "
-                            + obj.getClass().getName());
-                }
-            }
+    /**
+     *  Checks if the given {@link CommonHyphenation} is present in the cache -
+     *  if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param chy the CommonHyphenation instance to check for
+     *  @return the cached instance
+     */
+    public CommonHyphenation fetch(CommonHyphenation chy) {
 
-        }
+        return (CommonHyphenation) fetch((Object) chy);
+    }
 
-        // Adds a new or replaces an existing entry with obj that has the same hash code
-        map.put(hashCode, new WeakReference<T>(obj));
-        attemptCleanup();
-        return obj;
+    /**
+     *  Checks if the given {@link CommonFont} is present in the cache -
+     *  if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param cf the CommonFont instance to check for
+     *  @return the cached instance
+     */
+    public CommonFont fetch(CommonFont cf) {
 
-        /*
-         * Another thread might add first. We could check this using map.replace() instead of
-         * map.put() and then recursively call fetch(obj). But if in the meantime, garbage
-         * collection kicks in, we might end up with a StackOverflowException. Not caching an entry
-         * is tolerable, after all it's configurable.
-         */
+        return (CommonFont) fetch((Object) cf);
     }
 
+    /**
+     *  Checks if the given {@link CommonBorderPaddingBackground} is present in the cache -
+     *  if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param cbpb the CommonBorderPaddingBackground instance to check for
+     *  @return the cached instance
+     */
+    public CommonBorderPaddingBackground fetch(CommonBorderPaddingBackground cbpb) {
 
-    private void attemptCleanup() {
-        if ((putCounter.incrementAndGet() % 10000) != 0) {
-            return;
-        }
-        
-        // Lock as there is no need for concurrent cleanup and protect us, on JDK5, from
-        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6312056
-       if(cleanupLock.tryLock()) {
-            try {
-                cleanReclaimedMapEntries();
-            } finally {
-                cleanupLock.unlock();
-            }
-       }
+        return (CommonBorderPaddingBackground) fetch((Object) cbpb);
     }
 
-    private void cleanReclaimedMapEntries() {
-        Iterator<Map.Entry<Integer, WeakReference<T>>> mapIt = map.entrySet().iterator();
-        while (mapIt.hasNext()) {
-            Map.Entry<Integer, WeakReference<T>> entry = mapIt.next();
-            WeakReference<T> weakRef = entry.getValue();
-            T r = weakRef.get();
-            if (r == null) {
-                mapIt.remove();
-            }
-        }
+    /**
+     *  Checks if the given {@link CommonBorderPaddingBackground.BorderInfo} is present
+     *  in the cache - if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param bi the BorderInfo instance to check for
+     *  @return the cached instance
+     */
+    public CommonBorderPaddingBackground.BorderInfo fetch(
+            CommonBorderPaddingBackground.BorderInfo bi) {
+        return (CommonBorderPaddingBackground.BorderInfo) fetch((Object) bi);
     }
 
-    private boolean eq(Object p, Object q) {
-        return (p == q || p.equals(q));
+    /**
+     *  Checks if the given {@link org.apache.fop.fo.flow.Marker.MarkerAttribute} is present
+     *  in the cache - if so, returns a reference to the cached instance.
+     *  Otherwise the given object is added to the cache and returned.
+     *
+     *  @param ma the MarkerAttribute instance to check for
+     *  @return the cached instance
+     */
+    public Marker.MarkerAttribute fetch(
+            Marker.MarkerAttribute ma) {
+        return (Marker.MarkerAttribute) fetch((Object) ma);
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return super.toString() + "[runtimeType=" + this.runtimeType + "]";
     }
+
+
 }
diff --git src/java/org/apache/fop/fo/properties/StringProperty.java src/java/org/apache/fop/fo/properties/StringProperty.java
index 2a8ac9f..9bbe330 100644
--- src/java/org/apache/fop/fo/properties/StringProperty.java
+++ src/java/org/apache/fop/fo/properties/StringProperty.java
@@ -78,8 +78,8 @@ public final class StringProperty extends Property {
     }
 
     /** cache containing all canonical StringProperty instances */
-    private static final PropertyCache<StringProperty> CACHE
-        = new PropertyCache<StringProperty>();
+    private static final PropertyCache CACHE
+        = new PropertyCache(StringProperty.class);
 
     /** canonical instance for empty strings */
     public static final StringProperty EMPTY_STRING_PROPERTY = new StringProperty("");
@@ -104,7 +104,8 @@ public final class StringProperty extends Property {
         if ("".equals(str) || str == null) {
             return EMPTY_STRING_PROPERTY;
         } else {
-            return CACHE.fetch(new StringProperty(str));
+            return (StringProperty)CACHE.fetch(
+                       new StringProperty(str));
         }
     }
 
diff --git src/java/org/apache/fop/fo/properties/TableColLength.java src/java/org/apache/fop/fo/properties/TableColLength.java
index d06936f..ccb85bc 100644
--- src/java/org/apache/fop/fo/properties/TableColLength.java
+++ src/java/org/apache/fop/fo/properties/TableColLength.java
@@ -111,27 +111,4 @@ public class TableColLength extends LengthProperty {
         return (Double.toString(tcolUnits) + " table-column-units");
     }
 
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((column == null) ? 0 : column.hashCode());
-        long temp;
-        temp = Double.doubleToLongBits(tcolUnits);
-        result = prime * result + (int) (temp ^ (temp >>> 32));
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (!(obj instanceof TableColLength)) {
-            return false;
-        }
-        TableColLength other = (TableColLength) obj;
-        return Property.eq(column, other.column)
-                && Double.doubleToLongBits(tcolUnits) == Double.doubleToLongBits(other.tcolUnits);
-    }
 }
diff --git src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java
index 0315e0e..59a6caf 100644
--- src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java
+++ src/java/org/apache/fop/fo/properties/ToBeImplementedProperty.java
@@ -40,14 +40,15 @@ public class ToBeImplementedProperty extends Property {
             super(propId);
         }
 
-        @Override
+        /** {@inheritDoc} */
         public Property convertProperty(Property p,
                                         PropertyList propertyList, FObj fo) {
             if (p instanceof ToBeImplementedProperty) {
                 return p;
             }
 
-            ToBeImplementedProperty val = new ToBeImplementedProperty(getPropId());
+            ToBeImplementedProperty val
+                = new ToBeImplementedProperty(getPropId());
             return val;
         }
     }
@@ -66,19 +67,5 @@ public class ToBeImplementedProperty extends Property {
 //         log.warn("property - \"" + propName
 //                                + "\" is not implemented yet.");
     }
-
-    @Override
-    public int hashCode() {
-        return 0;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        return true;
-        /*
-         * Since a PropertyCache is not used here, returning true helps the PropertyCache when a non
-         * implemented property is part of an implemented one.
-         */
-    }
 }
 
diff --git src/java/org/apache/fop/fo/properties/URIProperty.java src/java/org/apache/fop/fo/properties/URIProperty.java
index f10e765..6465faf 100644
--- src/java/org/apache/fop/fo/properties/URIProperty.java
+++ src/java/org/apache/fop/fo/properties/URIProperty.java
@@ -19,16 +19,16 @@
 
 package org.apache.fop.fo.properties;
 
-import static org.apache.fop.fo.Constants.PR_X_XML_BASE;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-
 import org.apache.fop.datatypes.URISpecification;
 import org.apache.fop.fo.FObj;
 import org.apache.fop.fo.PropertyList;
 import org.apache.fop.fo.expr.PropertyException;
 
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import static org.apache.fop.fo.Constants.PR_X_XML_BASE;
+
 /**
  * Class modeling a property that has a value of type &lt;uri-specification>.
  * The purpose is mainly to support resolution of a specified
@@ -144,25 +144,5 @@ public class URIProperty extends Property {
             return p;
         }
     }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 17;
-        result = prime * result + ((resolvedURI == null) ? 0 : resolvedURI.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof URIProperty)) {
-            return false;
-        }
-        URIProperty other = (URIProperty) obj;
-        return Property.eq(resolvedURI, other.resolvedURI);
-    }
     
 }
