diff --git a/docs/authors.rst b/docs/authors.rst
index 8825321a..0480f295 100644
--- a/docs/authors.rst
+++ b/docs/authors.rst
@@ -125,3 +125,4 @@ Authors
 * Vishal Pandey
 * Vladimir Nani
 * Abhineet Tamrakar
+* Shalom Nyende
diff --git a/docs/changelog.rst b/docs/changelog.rst
index a0a4db76..e5ebfb31 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -5,6 +5,7 @@ Changelog
 ------------------
 
 New flavors:
+- Kenya localflavor
 
 - Nepal LocalFlavor: Support for Nepal added
   (`gh-451 <https://github.com/django/django-localflavor/pull/451>`_).
diff --git a/localflavor/ke/__init__.py b/localflavor/ke/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/localflavor/ke/deprecation.py b/localflavor/ke/deprecation.py
new file mode 100644
index 00000000..fb80ff5f
--- /dev/null
+++ b/localflavor/ke/deprecation.py
@@ -0,0 +1,2 @@
+class RemovedInLocalflavor30Warning(PendingDeprecationWarning):
+    ...
\ No newline at end of file
diff --git a/localflavor/ke/forms.py b/localflavor/ke/forms.py
new file mode 100644
index 00000000..3c6f929b
--- /dev/null
+++ b/localflavor/ke/forms.py
@@ -0,0 +1,199 @@
+"""Kenya-specific Form Helpers"""
+
+import re
+
+from django.forms import ValidationError
+from django.forms.fields import CharField, RegexField, Select
+from django.utils.translation import gettext_lazy as _
+
+from .ke_counties import COUNTY_CHOICES
+
+ke_po_box_re = re.compile(r"\A\d{5,5}\Z")
+ke_kra_pin_regex = re.compile(r"^(A|P)\d{9}[A-Z]$")
+ke_passport_regex = re.compile(r"^[A-Z]\d{6,7}$")
+ke_national_id_regex = re.compile(r"^\d{7,8}$")
+
+
+class KEPostalCodeField(CharField):
+    """
+    A form field that validates its input as a Kenyan Postal Code.
+    .. versionadded:: 4.0
+    """
+
+    default_error_messages = {
+        "invalid": _("Enter a valid Kenyan Postal code in the format 12345")
+    }
+
+    def clean(self, value: str):
+        """Validates KE Postal Code
+
+        Args:
+            value (_type_): _description_
+
+        Raises:
+            ValidationError: _description_
+
+        Returns:
+            _type_: _description_
+        """
+        value = super().clean(value)
+        if value in self.empty_values:
+            return self.empty_value
+
+        # Strip out spaces and dashes
+        value = value.replace(" ", "").replace("-", "")
+        match = re.match(ke_po_box_re, value)
+        if not match:
+            raise ValidationError(self.error_messages.get("invalid"))
+        return value
+
+
+class KEKRAPINField(CharField):
+    """
+    TODO
+
+    A form field that validates input as a Kenya Revenue Authority PIN
+    (Personal Identification Number) Number.
+
+    A Kenyan KRA (Kenya Revenue Authority) PIN (Personal Identification Number)
+
+    is typically 11 characters long, consisting of the letter 'A' or 'P' followed
+
+    by 9 digits and ending with a letter (e.g., A123456789B or P987654321C).
+
+    Validates 2 different formats:
+
+        POXXXXXXXX - Company/Institution
+
+        AXXXXXXXXX - Individuals
+
+    .. versionadded:: 4.0
+        
+    """
+
+    default_error_messages = {
+        "invalid": _(
+            "Enter a valid Kenyan KRA PIN Number in the format A123456789B or P987654321C"
+        ),
+    }
+
+    def clean(self, value):
+        """Runs the validation checks
+
+        Args:
+            value (_type_): _description_
+
+        Raises:
+            ValidationError: _description_
+
+        Returns:
+            _type_: _description_
+        """
+        value = super().clean(value)
+        if value in self.empty_values:
+            return self.empty_value
+
+        # Strip out spaces and dashes
+        value = value.replace(" ", "").replace("-", "")
+        match = re.match(ke_kra_pin_regex, value)
+        if not match:
+            raise ValidationError(self.error_messages.get("invalid"))
+        return value.upper()
+
+
+class KENationalIDNumberField(CharField):
+    """
+    A form field that validates its input as a Kenyan National ID Number.
+    .. versionadded:: 4.0
+    """
+
+    default_error_messages = {
+        "invalid": _(
+            "Enter a valid Kenyan National ID Number in the format 1234567 or 12345678"
+        )
+    }
+
+    def clean(self, value):
+        """Runs the validation checks for KE National ID Number"""
+        value = super().clean(value)
+        if value in self.empty_values:
+            return self.empty_value
+
+        # Strip out spaces and dashes
+        value = value.replace(" ", "").replace("-", "")
+        match = re.match(ke_national_id_regex, value)
+        if not match:
+            raise ValidationError(self.error_messages.get("invalid"))
+        return value
+
+
+class KEPassportNumberField(CharField):
+    """
+    A form field that validates its input as a Kenyan Passport Number.
+    .. versionadded:: 4.0
+    """
+
+    default_error_messages = {
+        "invalid": _(
+            "Enter a valid Kenyan Passport Number in the format A123456 or B1234567"
+        )
+    }
+
+    def clean(self, value):
+        """Runs the validation checks for KE Passport Number"""
+        value = super().clean(value)
+        if value in self.empty_values:
+            return self.empty_value
+
+        # Strip out spaces and dashes
+        value = value.replace(" ", "").replace("-", "")
+        match = re.match(ke_passport_regex, value)
+        if not match:
+            raise ValidationError(self.error_messages.get("invalid"))
+        return value.upper()
+
+
+class KENSSFNumberField(RegexField):
+    """
+    TODO
+
+    Kenya National Social Security Fund
+    """
+
+    ...
+
+
+class KENHIFNumberField(RegexField):
+    """
+    TODO
+
+    Kenya National Hospital Insurance Fund
+    """
+
+    ...
+
+
+class KECompanyRegNumberField(RegexField):
+    """
+    Kenya Companies Reg. Number
+    """
+
+    ...
+
+
+class KEPayBillNumber(RegexField):
+    """
+    MPESA PayBill
+    """
+
+    ...
+
+
+class KECountySelectField(Select):
+    """
+    A Select widget listing Kenyan Counties as the choices
+    .. versionadded:: 4.0
+    """
+
+    def __init__(self, attrs=None) -> None:
+        super().__init__(attrs, choices=COUNTY_CHOICES)
diff --git a/localflavor/ke/ke_counties.py b/localflavor/ke/ke_counties.py
new file mode 100644
index 00000000..0536e632
--- /dev/null
+++ b/localflavor/ke/ke_counties.py
@@ -0,0 +1,56 @@
+"""
+Kenya Counties Data
+"""
+
+from django.utils.translation import gettext_lazy as _
+
+# The 47 counties of Kenya
+COUNTY_CHOICES = (
+    ("MOMBASA", _("MOMBASA")),
+    ("KWALE", _("KWALE")),
+    ("KILIFI", _("KILIFI")),
+    ("TANA RIVER", _("TANA RIVER")),
+    ("LAMU", _("LAMU")),
+    ("TAITA-TAVETA", _("TAITA-TAVETA")),
+    ("GARISSA", _("GARISSA")),
+    ("WAJIR", _("WAJIR")),
+    ("MANDERA", _("MANDERA")),
+    ("MARSABIT", _("MARSABIT")),
+    ("ISIOLO", _("ISIOLO")),
+    ("MERU", _("MERU")),
+    ("THARAKA-NITHI", _("THARAKA-NITHI")),
+    ("EMBU", _("EMBU")),
+    ("KITUI", _("KITUI")),
+    ("MACHAKOS", _("MACHAKOS")),
+    ("MAKUENI", _("MAKUENI")),
+    ("NYANDARUA", _("NYANDARUA")),
+    ("NYERI", _("NYERI")),
+    ("KIRINYAGA", _("KIRINYAGA")),
+    ("MURANGA", _("MURANGA")),
+    ("KIAMBU", _("KIAMBU")),
+    ("TURKANA", _("TURKANA")),
+    ("WEST POKOT", _("WEST POKOT")),
+    ("SAMBURU", _("SAMBURU")),
+    ("TRANS-NZOIA", _("TRANS-NZOIA")),
+    ("UASIN GISHU", _("UASIN GISHU")),
+    ("ELGEYO-MARAKWET", _("ELGEYO-MARAKWET")),
+    ("NANDI", _("NANDI")),
+    ("BARINGO", _("BARINGO")),
+    ("LAIKIPIA", _("LAIKIPIA")),
+    ("NAKURU", _("NAKURU")),
+    ("NAROK", _("NAROK")),
+    ("KAJIADO", _("KAJIADO")),
+    ("KERICHO", _("KERICHO")),
+    ("BOMET", _("BOMET")),
+    ("KAKAMEGA", _("KAKAMEGA")),
+    ("VIHIGA", _("VIHIGA")),
+    ("BUNGOMA", _("BUNGOMA")),
+    ("BUSIA", _("BUSIA")),
+    ("SIAYA", _("SIAYA")),
+    ("KISUMU", _("KISUMU")),
+    ("HOMA BAY", _("HOMA BAY")),
+    ("MIGORI", _("MIGORI")),
+    ("KISII", _("KISII")),
+    ("NYAMIRA", _("NYAMIRA")),
+    ("NAIROBI", _("NAIROBI")),
+)
diff --git a/localflavor/ke/models.py b/localflavor/ke/models.py
new file mode 100644
index 00000000..73667c6a
--- /dev/null
+++ b/localflavor/ke/models.py
@@ -0,0 +1,34 @@
+from typing import Any
+from django.db.models import CharField
+from django.utils.translation import gettext_lazy as _
+
+from .forms import (
+    KENationalIDNumberField,
+    KEKRAPINField,
+    KENHIFNumberField,
+    KENSSFNumberField,
+    KEPassportNumberField,
+    KEPostalCodeField as KEPostalCodeFormField,
+)
+
+
+class KEPostalCodeField(CharField):
+    """
+    A model field that stores the Kenyan Postal Codes
+    .. versionadded:: 4.0
+    """
+    description = _("Kenya Postal Code")
+
+    def __init__(self, *args, **kwargs) -> None:
+        kwargs.update(max_length=8)
+        super().__init__(*args, **kwargs)
+
+    def formfield(self, **kwargs) -> Any:
+        defaults = {"form_class": KEPostalCodeFormField}
+        defaults.update(kwargs)
+        return super().formfield(**defaults)
+    
+
+
+        
+        
\ No newline at end of file
diff --git a/tests/test_ke.py b/tests/test_ke.py
new file mode 100644
index 00000000..4446e191
--- /dev/null
+++ b/tests/test_ke.py
@@ -0,0 +1,59 @@
+from django.test import SimpleTestCase
+from django.forms import ValidationError
+from .forms import KEPostalCodeField, KEKRAPINField, KENationalIDNumberField, KEPassportNumberField
+
+class KEPostalCodeFieldTest(SimpleTestCase):
+    def test_valid_postal_code(self):
+        field = KEPostalCodeField()
+        valid_postal_codes = ["12345", "54321"]
+        for postal_code in valid_postal_codes:
+            self.assertEqual(field.clean(postal_code), "12345")
+
+    def test_invalid_postal_code(self):
+        field = KEPostalCodeField()
+        invalid_postal_codes = ["1234", "ABCDE", "12 345", "12-345"]
+        for postal_code in invalid_postal_codes:
+            with self.assertRaises(ValidationError):
+                field.clean(postal_code)
+
+class KEKRAPINFieldTest(SimpleTestCase):
+    def test_valid_kra_pin(self):
+        field = KEKRAPINField()
+        valid_pins = ["A123456789B", "P987654321C"]
+        for pin in valid_pins:
+            self.assertEqual(field.clean(pin), pin)
+
+    def test_invalid_kra_pin(self):
+        field = KEKRAPINField()
+        invalid_pins = ["1234567890", "A123456789", "P987654321", "A12-3456789B"]
+        for pin in invalid_pins:
+            with self.assertRaises(ValidationError):
+                field.clean(pin)
+
+class KENationalIDNumberFieldTest(SimpleTestCase):
+    def test_valid_national_id(self):
+        field = KENationalIDNumberField()
+        valid_ids = ["1234567", "12345678"]
+        for id_number in valid_ids:
+            self.assertEqual(field.clean(id_number), id_number)
+
+    def test_invalid_national_id(self):
+        field = KENationalIDNumberField()
+        invalid_ids = ["12345", "12345A", "12-34567", "123456789"]
+        for id_number in invalid_ids:
+            with self.assertRaises(ValidationError):
+                field.clean(id_number)
+
+class KEPassportNumberFieldTest(SimpleTestCase):
+    def test_valid_passport_number(self):
+        field = KEPassportNumberField()
+        valid_passports = ["A123456", "B1234567"]
+        for passport in valid_passports:
+            self.assertEqual(field.clean(passport), passport)
+
+    def test_invalid_passport_number(self):
+        field = KEPassportNumberField()
+        invalid_passports = ["12345", "A1234567B", "AB-123456"]
+        for passport in invalid_passports:
+            with self.assertRaises(ValidationError):
+                field.clean(passport)