diff --git a/theories/fin_map_dom.v b/theories/fin_map_dom.v
index 6d50c11ad8a8393e1e8e3a7f75638f1b6c25fbbd..1500b623a43f0c9c16345c19b89c3874c2042628 100644
--- a/theories/fin_map_dom.v
+++ b/theories/fin_map_dom.v
@@ -19,6 +19,13 @@ Class FinMapDom K M D `{∀ A, Dom (M A) D, FMap M,
 Section fin_map_dom.
 Context `{FinMapDom K M D}.
 
+Lemma dom_map_filter {A} (P : K * A → Prop) `{!∀ x, Decision (P x)} (m : M A):
+  dom D (filter P m) ⊆ dom D m.
+Proof.
+  intros ?. rewrite 2!elem_of_dom.
+  destruct 1 as [?[Eq _]%map_filter_lookup_Some]. by eexists.
+Qed.
+
 Lemma elem_of_dom_2 {A} (m : M A) i x : m !! i = Some x → i ∈ dom D m.
 Proof. rewrite elem_of_dom; eauto. Qed.
 Lemma not_elem_of_dom {A} (m : M A) i : i ∉ dom D m ↔ m !! i = None.
diff --git a/theories/fin_maps.v b/theories/fin_maps.v
index 6e6d1ddce9a785296f500d7d41f8cb1659e44bdb..b52ce660da414e8e6279aa7a966e424c30ae5d13 100644
--- a/theories/fin_maps.v
+++ b/theories/fin_maps.v
@@ -130,6 +130,9 @@ is unspecified. *)
 Definition map_fold `{FinMapToList K A M} {B}
   (f : K → A → B → B) (b : B) : M → B := foldr (curry f) b ∘ map_to_list.
 
+Instance map_filter `{FinMapToList K A M, Insert K A M, Empty M} : Filter (K * A) M :=
+  λ P _, map_fold (λ k v m, if decide (P (k,v)) then <[k := v]>m else m) ∅.
+
 (** * Theorems *)
 Section theorems.
 Context `{FinMap K M}.
@@ -1002,6 +1005,53 @@ Proof.
     assert (m !! j = Some y) by (apply Hm; by right). naive_solver.
 Qed.
 
+(** ** The filter operation *)
+Section map_Filter.
+  Context {A} (P : K * A → Prop) `{!∀ x, Decision (P x)}.
+  Implicit Types m : M A.
+
+  Lemma map_filter_lookup_Some m i x :
+    filter P m !! i = Some x ↔ m !! i = Some x ∧ P (i,x).
+  Proof.
+    revert m i x. apply (map_fold_ind (λ m1 m2,
+      ∀ i x, m1 !! i = Some x ↔ m2 !! i = Some x ∧ P _)); intros i x.
+    - rewrite lookup_empty. naive_solver.
+    - intros m m' Hm Eq j y. case_decide; case (decide (j = i))as [->|?].
+      + rewrite 2!lookup_insert. naive_solver.
+      + rewrite !lookup_insert_ne by done. by apply Eq.
+      + rewrite Eq, Hm, lookup_insert. naive_solver.
+      + by rewrite lookup_insert_ne.
+  Qed.
+
+  Lemma map_filter_lookup_None m i :
+    filter P m !! i = None ↔ m !! i = None ∨ ∀ x, m !! i = Some x → ¬ P (i,x).
+  Proof.
+    rewrite eq_None_not_Some. unfold is_Some.
+    setoid_rewrite map_filter_lookup_Some. naive_solver.
+  Qed.
+
+  Lemma map_filter_lookup_eq m1 m2 :
+    (∀ k x, P (k,x) → m1 !! k = Some x ↔ m2 !! k = Some x) →
+    filter P m1 = filter P m2.
+  Proof.
+    intros HP. apply map_eq. intros i. apply option_eq; intros x.
+    rewrite !map_filter_lookup_Some. naive_solver.
+  Qed.
+
+  Lemma map_filter_lookup_insert m i x :
+    P (i,x) → <[i:=x]> (filter P m) = filter P (<[i:=x]> m).
+  Proof.
+    intros HP. apply map_eq. intros j. apply option_eq; intros y.
+    destruct (decide (j = i)) as [->|?].
+    - rewrite map_filter_lookup_Some, !lookup_insert. naive_solver.
+    - rewrite lookup_insert_ne, !map_filter_lookup_Some, lookup_insert_ne by done.
+      naive_solver.
+  Qed.
+
+  Lemma map_filter_empty : filter P (∅ : M A) = ∅.
+  Proof. apply map_fold_empty. Qed.
+End map_Filter.
+
 (** ** Properties of the [map_Forall] predicate *)
 Section map_Forall.
 Context {A} (P : K → A → Prop).