diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
index c03a5c9913..4629770ce0 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
@@ -166,6 +166,13 @@ public class ContentMirrorStoreStrategy implements IndexStoreStrategy {
             }
         };
     }
+    
+    @Override
+    public Iterable<IndexEntry> queryEntries(Filter filter, String indexName, NodeState indexMeta,
+            Iterable<String> values) {
+        // we don't support it since there is no actual need at the moment. See OAK-6578 and OAK-6506
+        throw new UnsupportedOperationException();
+    }
 
     @Nonnull
     Iterable<? extends ChildNodeEntry> getChildNodeEntries(@Nonnull
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/FilteringIndexStoreStrategy.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/FilteringIndexStoreStrategy.java
index d7dfb62cb7..ca49edec66 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/FilteringIndexStoreStrategy.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/FilteringIndexStoreStrategy.java
@@ -77,6 +77,12 @@ public class FilteringIndexStoreStrategy implements IndexStoreStrategy {
         return strategy.query(filter, indexName, indexMeta, values);
     }
 
+    @Override
+    public Iterable<IndexEntry> queryEntries(Filter filter, String indexName, NodeState indexMeta,
+            Iterable<String> values) {
+        return strategy.queryEntries(filter, indexName, indexMeta, values);
+    }
+
     @Override
     public long count(NodeState root, NodeState indexMeta, Set<String> values,
             int max) {
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java
index c540c5581d..99192dd8f6 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategy.java
@@ -64,6 +64,19 @@ public interface IndexStoreStrategy {
      * @return an iterator of paths
      */
     Iterable<String> query(Filter filter, String indexName, NodeState indexMeta, Iterable<String> values);
+    
+    /**
+     * Search for a given set of values, returning <tt>IndexEntry</tt> results (optional operation)
+     * 
+     * @param filter the filter (can optionally be used for optimized query execution)
+     * @param indexName the name of the index (for logging)
+     * @param indexMeta the index metadata node (may not be null)
+     * @param values values to look for (null to check for property existence)
+     * @return an iterator of index entries
+     * 
+     * @throws UnsupportedOperationException if the operation is not supported
+     */
+    Iterable<IndexEntry> queryEntries(Filter filter, String indexName, NodeState indexMeta, Iterable<String> values);
 
     /**
      * Count the occurrence of a given set of values. Used in calculating the
@@ -91,5 +104,68 @@ public interface IndexStoreStrategy {
     long count(Filter filter, NodeState root, NodeState indexMeta, Set<String> values, int max);
 
     String getIndexNodeName();
+    
+    /**
+     * An entry in the index
+     *
+     */
+    public static final class IndexEntry {
+        
+        private final String path;
+        private final String propertyValue;
+        
+        IndexEntry(String path, String propertyValue) {
+            this.path = path;
+            this.propertyValue = propertyValue;
+            
+        }
+        
+        public String getPath() {
+            return path;
+        }
+        
+        public String getPropertyValue() {
+            return propertyValue;
+        }
+
+        
+        
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + ((path == null) ? 0 : path.hashCode());
+            result = prime * result + ((propertyValue == null) ? 0 : propertyValue.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            IndexEntry other = (IndexEntry) obj;
+            if (path == null) {
+                if (other.path != null)
+                    return false;
+            } else if (!path.equals(other.path))
+                return false;
+            if (propertyValue == null) {
+                if (other.propertyValue != null)
+                    return false;
+            } else if (!propertyValue.equals(other.propertyValue))
+                return false;
+            return true;
+        }
+
+        @Override
+        public String toString() {
+            
+            return getClass().getSimpleName() + "# path: " + path + ", propertyValue: " + propertyValue;
+        }
+    }
 
 }
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
index 97d8bf5956..606df9c617 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/UniqueEntryStoreStrategy.java
@@ -119,26 +119,50 @@ public class UniqueEntryStoreStrategy implements IndexStoreStrategy {
     @Override
     public Iterable<String> query(final Filter filter, final String indexName, 
             final NodeState indexMeta, final Iterable<String> values) {
+        return query0(filter, indexName, indexMeta, values, new HitProducer<String>() {
+            @Override
+            public String produce(NodeState indexHit, String pathName) {
+                PropertyState s = indexHit.getProperty("entry");
+                return s.getValue(Type.STRING, 0);
+            }
+        });        
+    }
+
+    @Override
+    public Iterable<IndexEntry> queryEntries(Filter filter, String indexName, NodeState indexMeta,
+            Iterable<String> values) {
+        return query0(filter, indexName, indexMeta, values, new HitProducer<IndexEntry>() {
+            @Override
+            public IndexEntry produce(NodeState indexHit, String pathName) {
+                PropertyState s = indexHit.getProperty("entry");
+                return new IndexEntry(s.getValue(Type.STRING, 0), pathName);
+            }
+        });
+    }
+
+    private <T> Iterable<T> query0(Filter filter, String indexName, NodeState indexMeta,
+            Iterable<String> values, HitProducer<T> prod) {
         final NodeState index = indexMeta.getChildNode(getIndexNodeName());
-        return new Iterable<String>() {
+        return new Iterable<T>() {
             @Override
-            public Iterator<String> iterator() {
+            public Iterator<T> iterator() {
                 if (values == null) {
-                    return new Iterator<String>() {
+                    return new Iterator<T>() {
                         
                         Iterator<? extends ChildNodeEntry> it = index.getChildNodeEntries().iterator();
-
+                        
                         @Override
                         public boolean hasNext() {
                             return it.hasNext();
                         }
-
+                        
                         @Override
-                        public String next() {
-                            PropertyState s = it.next().getNodeState().getProperty("entry");
-                            return s.getValue(Type.STRING, 0);
+                        public T next() {
+                            ChildNodeEntry indexEntry = it.next();
+                            
+                            return prod.produce(indexEntry.getNodeState(), indexEntry.getName());
                         }
-
+                        
                         @Override
                         public void remove() {
                             it.remove();
@@ -146,21 +170,19 @@ public class UniqueEntryStoreStrategy implements IndexStoreStrategy {
                         
                     };
                 }
-                ArrayList<String> list = new ArrayList<String>();
+                ArrayList<T> list = new ArrayList<>();
                 for (String p : values) {
                     NodeState key = index.getChildNode(p);
                     if (key.exists()) {
                         // we have an entry for this value, so use it
-                        PropertyState s = key.getProperty("entry");
-                        String v = s.getValue(Type.STRING, 0);
-                        list.add(v);
+                        list.add(prod.produce(key, p));
                     }
                 }
                 return list.iterator();
             }
         };
     }
-
+    
     @Override
     public boolean exists(Supplier<NodeBuilder> index, String key) {
         return index.get().hasChildNode(key);
@@ -209,4 +231,16 @@ public class UniqueEntryStoreStrategy implements IndexStoreStrategy {
     public String getIndexNodeName() {
         return indexName;
     }
+
+    /**
+     * Creates a specific type of "hit" to return from the query methods
+     * 
+     * <p>Use primarily to reduce duplication when the query algorithms execute mostly the same steps but return different objects.</p>
+     * 
+     * @param <T> The type of Hit to produce
+     */
+    private interface HitProducer<T> {
+        T produce(NodeState indexHit, String pathName);
+    }
+    
 }
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategySharedTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategySharedTest.java
new file mode 100644
index 0000000000..add4c9a0f1
--- /dev/null
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/IndexStoreStrategySharedTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.plugins.index.property.strategy;
+
+import static com.google.common.base.Suppliers.memoize;
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.assertThat;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+
+import org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy.IndexEntry;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import com.google.common.base.Supplier;
+
+@RunWith(Parameterized.class)
+public class IndexStoreStrategySharedTest {
+    
+    private static final Set<String> EMPTY = newHashSet();
+    private String indexName;
+    private NodeBuilder indexMeta;
+    private IndexStoreStrategy store;
+    
+    @Parameterized.Parameters(name="{0}")
+    public static Collection<Object[]> fixtures() {
+        return Arrays.asList(new Object[][] {
+                new Object[] { new UniqueEntryStoreStrategy() }
+        });
+    }
+    
+    public IndexStoreStrategySharedTest(IndexStoreStrategy store) {
+        this.store = store;
+    }
+    
+    @Before
+    public void fillIndex() throws Exception {
+        indexName = "foo";
+        
+        NodeState root = EMPTY_NODE;
+        indexMeta = root.builder();
+        Supplier<NodeBuilder> index = memoize(() -> indexMeta.child(INDEX_CONTENT_NODE_NAME));
+        store.update(index, "/some/node1", null, null, EMPTY, newHashSet("key1"));
+        store.update(index, "/some/node2", null, null, EMPTY, newHashSet("key2"));
+    }
+
+    @Test
+    public void queryEntries_All() {
+        
+        Iterable<IndexEntry> hits = store.queryEntries(FilterImpl.newTestInstance(), indexName, indexMeta.getNodeState(), null);
+        
+        assertThat(hits, containsInAnyOrder(new IndexEntry("/some/node1", "key1"), new IndexEntry("/some/node2", "key2")));
+    }
+    
+    @Test
+    public void queryEntries_some() {
+
+        Iterable<IndexEntry> hits = store.queryEntries(FilterImpl.newTestInstance(), indexName, indexMeta.getNodeState(), Arrays.asList("key1"));
+        
+        assertThat(hits, containsInAnyOrder(new IndexEntry("/some/node1", "key1")));
+    }
+}
