diff --git a/pallets/distance/src/mock.rs b/pallets/distance/src/mock.rs
index edcfedbfe7cc4ee222045d5e91ff21a0359be511..f837bac853882dd99ba6a608eb94e2e38b315245 100644
--- a/pallets/distance/src/mock.rs
+++ b/pallets/distance/src/mock.rs
@@ -243,6 +243,7 @@ impl pallet_identity::Config for Test {
     type IdtyNameValidator = IdtyNameValidatorTestImpl;
     type OnNewIdty = ();
     type OnRemoveIdty = ();
+    type OwnerKeyChangePermission = ();
     type RuntimeEvent = RuntimeEvent;
     type Signature = TestSignature;
     type Signer = UintAuthorityId;
diff --git a/pallets/duniter-wot/src/mock.rs b/pallets/duniter-wot/src/mock.rs
index 9ebef148ce76c05eb0750d4b4ee93060ecd2a0dc..ddb4bf63f64b807a7a40abe2aa40a9d91a43ad57 100644
--- a/pallets/duniter-wot/src/mock.rs
+++ b/pallets/duniter-wot/src/mock.rs
@@ -123,6 +123,7 @@ impl pallet_identity::Config for Test {
     type IdtyNameValidator = IdtyNameValidatorTestImpl;
     type OnNewIdty = DuniterWot;
     type OnRemoveIdty = DuniterWot;
+    type OwnerKeyChangePermission = ();
     type RuntimeEvent = RuntimeEvent;
     type Signature = TestSignature;
     type Signer = UintAuthorityId;
diff --git a/pallets/identity/src/lib.rs b/pallets/identity/src/lib.rs
index f0f70e6c5d829d6145473270a5d0a7456791791f..f09c2d31c59354158094edd155d75ba4676f6c89 100644
--- a/pallets/identity/src/lib.rs
+++ b/pallets/identity/src/lib.rs
@@ -132,6 +132,9 @@ pub mod pallet {
         /// The type used to check account worthiness.
         type CheckAccountWorthiness: CheckAccountWorthiness<Self>;
 
+        /// Handler that checks the necessary permissions for an identity's owner key change.
+        type OwnerKeyChangePermission: CheckKeyChangeAllowed<Self>;
+
         /// Custom data to store in each identity.
         type IdtyData: Clone
             + Codec
@@ -453,6 +456,12 @@ pub mod pallet {
                 Error::<T>::OwnerKeyAlreadyUsed
             );
 
+            // Ensure that the key is not currently as a validator
+            ensure!(
+                T::OwnerKeyChangePermission::check_allowed(&idty_index),
+                Error::<T>::OwnerKeyUsedAsValidator
+            );
+
             let block_number = frame_system::Pallet::<T>::block_number();
             let maybe_old_old_owner_key =
                 if let Some((old_owner_key, last_change)) = idty_value.old_owner_key {
@@ -690,6 +699,8 @@ pub mod pallet {
         AccountNotExist,
         /// Insufficient balance to create an identity.
         InsufficientBalance,
+        /// Owner key currently used as validator.
+        OwnerKeyUsedAsValidator,
     }
 
     // INTERNAL FUNCTIONS //
diff --git a/pallets/identity/src/mock.rs b/pallets/identity/src/mock.rs
index dcd757c0b2f1da86cc793c31951ef673921c95fe..92380ce2cc3d7cb54fd2bf45fa2c941de787608b 100644
--- a/pallets/identity/src/mock.rs
+++ b/pallets/identity/src/mock.rs
@@ -116,6 +116,7 @@ impl pallet_identity::Config for Test {
     type IdtyNameValidator = IdtyNameValidatorTestImpl;
     type OnNewIdty = ();
     type OnRemoveIdty = ();
+    type OwnerKeyChangePermission = ();
     type RuntimeEvent = RuntimeEvent;
     type Signature = Signature;
     type Signer = AccountPublic;
diff --git a/pallets/identity/src/traits.rs b/pallets/identity/src/traits.rs
index 73c759cffbf0a2c9130a033ef87f583ffd6a1aef..8366d1cff76022599feb2d118e622128cc12a59e 100644
--- a/pallets/identity/src/traits.rs
+++ b/pallets/identity/src/traits.rs
@@ -94,3 +94,15 @@ impl<AccountId, IdtyIndex> LinkIdty<AccountId, IdtyIndex> for () {
         Ok(())
     }
 }
+
+/// Trait for checking whether a key change is allowed for a given identity.
+pub trait CheckKeyChangeAllowed<T: Config> {
+    /// Determines if a key change is allowed for the given identity.
+    fn check_allowed(account_id: &T::IdtyIndex) -> bool;
+}
+
+impl<T: Config> CheckKeyChangeAllowed<T> for () {
+    fn check_allowed(_: &T::IdtyIndex) -> bool {
+        true
+    }
+}
diff --git a/pallets/quota/src/mock.rs b/pallets/quota/src/mock.rs
index e533345ea301040f456ced63ddb89ba05597c895..a21f3b85c552e77c4ff63397e2ebf5b60be8e812 100644
--- a/pallets/quota/src/mock.rs
+++ b/pallets/quota/src/mock.rs
@@ -157,6 +157,7 @@ impl pallet_identity::Config for Test {
     type IdtyNameValidator = IdtyNameValidatorTestImpl;
     type OnNewIdty = ();
     type OnRemoveIdty = ();
+    type OwnerKeyChangePermission = ();
     type RuntimeEvent = RuntimeEvent;
     type Signature = Signature;
     type Signer = AccountPublic;
diff --git a/resources/metadata.scale b/resources/metadata.scale
index 7b3fc4e7c424afabf32ed020c7739a4ab0be673f..021ed2e3d4d1432e070d9cfe9600f6fc64df121d 100644
Binary files a/resources/metadata.scale and b/resources/metadata.scale differ
diff --git a/runtime/common/src/handlers.rs b/runtime/common/src/handlers.rs
index fa247d1c5ccd530cd4c749b2bd0f9034ce7c1949..cb8a819bb6fa7800498965d4bf0d7c885c8821b7 100644
--- a/runtime/common/src/handlers.rs
+++ b/runtime/common/src/handlers.rs
@@ -165,3 +165,17 @@ where
         }
     }
 }
+
+/// Runtime handler OwnerKeyChangePermission.
+pub struct OwnerKeyChangePermissionHandler<Runtime>(core::marker::PhantomData<Runtime>);
+impl<
+        Runtime: frame_system::Config
+            + pallet_identity::Config<IdtyIndex = IdtyIndex>
+            + pallet_authority_members::Config<MemberId = IdtyIndex>,
+    > pallet_identity::traits::CheckKeyChangeAllowed<Runtime>
+    for OwnerKeyChangePermissionHandler<Runtime>
+{
+    fn check_allowed(idty_index: &IdtyIndex) -> bool {
+        !pallet_authority_members::Pallet::<Runtime>::online().contains(idty_index)
+    }
+}
diff --git a/runtime/common/src/pallets_config.rs b/runtime/common/src/pallets_config.rs
index b376b12d87490c963061e5f1dd8114f476527b36..3389823fa3434059b96789a47726b01afe85eb8a 100644
--- a/runtime/common/src/pallets_config.rs
+++ b/runtime/common/src/pallets_config.rs
@@ -470,6 +470,7 @@ macro_rules! pallets_config {
             type IdtyNameValidator = IdtyNameValidatorImpl;
             type OnNewIdty = OnNewIdtyHandler<Runtime>;
             type OnRemoveIdty = OnRemoveIdtyHandler<Runtime>;
+            type OwnerKeyChangePermission = OwnerKeyChangePermissionHandler<Runtime>;
             type RuntimeEvent = RuntimeEvent;
             type Signature = Signature;
             type Signer = <Signature as sp_runtime::traits::Verify>::Signer;
diff --git a/runtime/gdev/tests/integration_tests.rs b/runtime/gdev/tests/integration_tests.rs
index f6bbdf48d9d539098bab860f7099ab69edd0c09d..892894e5b2cde2ea3f0af9643e3d42e4f18ef68a 100644
--- a/runtime/gdev/tests/integration_tests.rs
+++ b/runtime/gdev/tests/integration_tests.rs
@@ -1361,6 +1361,31 @@ fn test_link_account() {
         })
 }
 
+/// test change owner key
+#[test]
+fn test_change_owner_key_validator_online() {
+    ExtBuilder::new(1, 3, 4).build().execute_with(|| {
+        let genesis_hash = System::block_hash(0);
+        let alice = AccountKeyring::Alice.to_account_id();
+        let ferdie = AccountKeyring::Ferdie.to_account_id();
+        let payload = (b"icok", genesis_hash, 1u32, alice.clone()).encode();
+        let signature = AccountKeyring::Alice.sign(&payload);
+
+        // Alice is an online validator
+        assert!(pallet_authority_members::OnlineAuthorities::<Runtime>::get().contains(&1));
+
+        // As an online validator she cannot change key
+        assert_noop!(
+            Identity::change_owner_key(
+                frame_system::RawOrigin::Signed(alice.clone()).into(),
+                ferdie.clone(),
+                signature.into()
+            ),
+            pallet_identity::Error::<gdev_runtime::Runtime>::OwnerKeyUsedAsValidator
+        );
+    })
+}
+
 /// test change owner key
 #[test]
 fn test_change_owner_key() {